home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / Other Langs / MacPerl ƒ / Perl Source ƒ / Perl / doio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-12  |  65.5 KB  |  3,115 lines  |  [TEXT/MPS ]

  1. /* $RCSfile: doio.c,v $$Revision: 4.0.1.6 $$Date: 92/06/11 21:08:16 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of the Perl Artistic License,
  6.  *    as specified in the README file.
  7.  *
  8.  * $Log:    doio.c,v $
  9.  * Revision 4.0.1.6  92/06/11  21:08:16  lwall
  10.  * patch34: some systems don't declare h_errno extern in header files
  11.  * 
  12.  * Revision 4.0.1.5  92/06/08  13:00:21  lwall
  13.  * patch20: some machines don't define ENOTSOCK in errno.h
  14.  * patch20: new warnings for failed use of stat operators on filenames with \n
  15.  * patch20: wait failed when STDOUT or STDERR reopened to a pipe
  16.  * patch20: end of file latch not reset on reopen of STDIN
  17.  * patch20: seek(HANDLE, 0, 1) went to eof because of ancient Ultrix workaround
  18.  * patch20: fixed memory leak on system() for vfork() machines
  19.  * patch20: get*by* routines now return something useful in a scalar context
  20.  * patch20: h_errno now accessible via $?
  21.  * 
  22.  * Revision 4.0.1.4  91/11/05  16:51:43  lwall
  23.  * patch11: prepared for ctype implementations that don't define isascii()
  24.  * patch11: perl mistook some streams for sockets because they return mode 0 too
  25.  * patch11: reopening STDIN, STDOUT and STDERR failed on some machines
  26.  * patch11: certain perl errors should set EBADF so that $! looks better
  27.  * patch11: truncate on a closed filehandle could dump
  28.  * patch11: stats of _ forgot whether prior stat was actually lstat
  29.  * patch11: -T returned true on NFS directory
  30.  * 
  31.  * Revision 4.0.1.3  91/06/10  01:21:19  lwall
  32.  * patch10: read didn't work from character special files open for writing
  33.  * patch10: close-on-exec wrongly set on system file descriptors
  34.  * 
  35.  * Revision 4.0.1.2  91/06/07  10:53:39  lwall
  36.  * patch4: new copyright notice
  37.  * patch4: system fd's are now treated specially
  38.  * patch4: added $^F variable to specify maximum system fd, default 2
  39.  * patch4: character special files now opened with bidirectional stdio buffers
  40.  * patch4: taintchecks could improperly modify parent in vfork()
  41.  * patch4: many, many itty-bitty portability fixes
  42.  * 
  43.  * Revision 4.0.1.1  91/04/11  17:41:06  lwall
  44.  * patch1: hopefully straightened out some of the Xenix mess
  45.  * 
  46.  * Revision 4.0  91/03/20  01:07:06  lwall
  47.  * 4.0 baseline.
  48.  * 
  49.  */
  50.  
  51. #include "EXTERN.h"
  52. #include "perl.h"
  53.  
  54. #ifdef HAS_SOCKET
  55. #include <sys/socket.h>
  56. #include <netdb.h>
  57. #ifndef ENOTSOCK
  58. #ifdef macintosh
  59. #include <TFileSpec.h>
  60. int choose(int, int, char *, void *, int, void *, int *);
  61. #include <errno.h>
  62. #include <sys/errno.h>
  63. #else
  64. #include <net/errno.h>
  65. #endif
  66. #endif
  67. #endif
  68.  
  69. #ifdef HAS_SELECT
  70. #ifdef I_SYS_SELECT
  71. #ifndef I_SYS_TIME
  72. #include <sys/select.h>
  73. #endif
  74. #endif
  75. #endif
  76.  
  77. #ifdef HOST_NOT_FOUND
  78. extern int h_errno;
  79. #endif
  80.  
  81. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  82. #include <sys/ipc.h>
  83. #ifdef HAS_MSG
  84. #include <sys/msg.h>
  85. #endif
  86. #ifdef HAS_SEM
  87. #include <sys/sem.h>
  88. #endif
  89. #ifdef HAS_SHM
  90. #include <sys/shm.h>
  91. #endif
  92. #endif
  93.  
  94. #ifdef I_PWD
  95. #include <pwd.h>
  96. #endif
  97. #ifdef I_GRP
  98. #include <grp.h>
  99. #endif
  100. #ifdef I_UTIME
  101. #include <utime.h>
  102. #endif
  103. #ifdef I_FCNTL
  104. #include <fcntl.h>
  105. #endif
  106. #ifdef I_SYS_FILE
  107. #include <sys/file.h>
  108. #endif
  109.  
  110. int laststatval = -1;
  111. int laststype = O_STAT;
  112.  
  113. static char* warn_nl = "Unsuccessful %s on filename containing newline";
  114.  
  115. bool
  116. do_open(stab,name,len)
  117. STAB *stab;
  118. register char *name;
  119. int len;
  120. {
  121.     FILE *fp;
  122.     register STIO *stio = stab_io(stab);
  123.     char *myname = savestr(name);
  124.     int result;
  125.     int fd;
  126.     int writing = 0;
  127.     char mode[3];        /* stdio file mode ("r\0" or "r+\0") */
  128.     FILE *saveifp = Nullfp;
  129.     FILE *saveofp = Nullfp;
  130.     char savetype = ' ';
  131.  
  132.     mode[0] = mode[1] = mode[2] = '\0';
  133.     name = myname;
  134.     forkprocess = 1;        /* assume true if no fork */
  135.     while (len && isSPACE(name[len-1]))
  136.     name[--len] = '\0';
  137.     if (!stio)
  138.     stio = stab_io(stab) = stio_new();
  139.     else if (stio->ifp) {
  140.     fd = fileno(stio->ifp);
  141.     if (stio->type == '-')
  142.         result = 0;
  143.     else if (fd <= maxsysfd) {
  144.         saveifp = stio->ifp;
  145.         saveofp = stio->ofp;
  146.         savetype = stio->type;
  147.         result = 0;
  148.     }
  149.     else if (stio->type == '|')
  150.         result = mypclose(stio->ifp);
  151.     else if (stio->ifp != stio->ofp) {
  152.         if (stio->ofp) {
  153.         result = fclose(stio->ofp);
  154.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  155.         }
  156.         else
  157.         result = fclose(stio->ifp);
  158.     }
  159.     else
  160.         result = fclose(stio->ifp);
  161.     if (result == EOF && fd > maxsysfd)
  162.         fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
  163.           stab_ename(stab));
  164.     stio->ofp = stio->ifp = Nullfp;
  165.     }
  166.     if (*name == '+' && len > 1 && name[len-1] != '|') {    /* scary */
  167.     mode[1] = *name++;
  168.     mode[2] = '\0';
  169.     --len;
  170.     writing = 1;
  171.     }
  172.     else  {
  173.     mode[1] = '\0';
  174.     }
  175.     stio->type = *name;
  176.     if (*name == '|') {
  177.     /*SUPPRESS 530*/
  178.     for (name++; isSPACE(*name); name++) ;
  179. #ifdef TAINT
  180.     taintenv();
  181.     taintproper("Insecure dependency in piped open");
  182. #endif
  183.     fp = mypopen(name,"w");
  184.     writing = 1;
  185.     }
  186.     else if (*name == '>') {
  187. #ifdef TAINT
  188.     taintproper("Insecure dependency in open");
  189. #endif
  190.     name++;
  191.     if (*name == '>') {
  192.         mode[0] = stio->type = 'a';
  193.         name++;
  194.     }
  195.     else
  196.         mode[0] = 'w';
  197.     writing = 1;
  198.     if (*name == '&') {
  199.       duplicity:
  200.         name++;
  201.         while (isSPACE(*name))
  202.         name++;
  203.         if (isDIGIT(*name))
  204.         fd = atoi(name);
  205.         else {
  206.         stab = stabent(name,FALSE);
  207.         if (!stab || !stab_io(stab)) {
  208. #ifdef EINVAL
  209.             errno = EINVAL;
  210. #endif
  211.             goto say_false;
  212.         }
  213.         if (stab_io(stab) && stab_io(stab)->ifp) {
  214.             fd = fileno(stab_io(stab)->ifp);
  215.             if (stab_io(stab)->type == 's')
  216.             stio->type = 's';
  217.         }
  218.         else
  219.             fd = -1;
  220.         }
  221.         if (!(fp = fdopen(fd = dup(fd),mode))) {
  222.         close(fd);
  223.         }
  224.     }
  225.     else {
  226.         while (isSPACE(*name))
  227.         name++;
  228.         if (strEQ(name,"-")) {
  229.         fp = stdout;
  230.         stio->type = '-';
  231.         }
  232.         else  {
  233.         fp = fopen(name,mode);
  234.         }
  235.     }
  236.     }
  237.     else {
  238.     if (*name == '<') {
  239.         mode[0] = 'r';
  240.         name++;
  241.         while (isSPACE(*name))
  242.         name++;
  243.         if (*name == '&')
  244.         goto duplicity;
  245.         if (strEQ(name,"-")) {
  246.         fp = stdin;
  247.         stio->type = '-';
  248.         }
  249.         else
  250.         fp = fopen(name,mode);
  251.     }
  252.     else if (name[len-1] == '|') {
  253. #ifdef TAINT
  254.         taintenv();
  255.         taintproper("Insecure dependency in piped open");
  256. #endif
  257.         name[--len] = '\0';
  258.         while (len && isSPACE(name[len-1]))
  259.         name[--len] = '\0';
  260.         /*SUPPRESS 530*/
  261.         for (; isSPACE(*name); name++) ;
  262.         fp = mypopen(name,"r");
  263.         stio->type = '|';
  264.     }
  265.     else {
  266.         stio->type = '<';
  267.         /*SUPPRESS 530*/
  268.         for (; isSPACE(*name); name++) ;
  269.         if (strEQ(name,"-")) {
  270.         fp = stdin;
  271.         stio->type = '-';
  272.         }
  273.         else
  274.         fp = fopen(name,"r");
  275.     }
  276.     }
  277.     if (!fp) {
  278.     if (dowarn && stio->type == '<' && index(name, '\n'))
  279.         warn(warn_nl, "open");
  280.     Safefree(myname);
  281.     goto say_false;
  282.     }
  283.     Safefree(myname);
  284.     if (stio->type &&
  285.       stio->type != '|' && stio->type != '-') {
  286.     if (fstat(fileno(fp),&statbuf) < 0) {
  287.         (void)fclose(fp);
  288.         goto say_false;
  289.     }
  290.     if (S_ISSOCK(statbuf.st_mode))
  291.         stio->type = 's';    /* in case a socket was passed in to us */
  292. #ifdef HAS_SOCKET
  293.     else if (
  294. #ifdef S_IFMT
  295.         !(statbuf.st_mode & S_IFMT)
  296. #else
  297.         !statbuf.st_mode
  298. #endif
  299.     ) {
  300.         int buflen = sizeof tokenbuf;
  301. #ifdef macintosh
  302.         if (getsockname(fileno(fp), (struct sockaddr *) &tokenbuf, &buflen) >= 0
  303. #else
  304.         if (getsockname(fileno(fp), tokenbuf, &buflen) >= 0
  305. #endif
  306.         || errno != ENOTSOCK)
  307.         stio->type = 's'; /* some OS's return 0 on fstat()ed socket */
  308.                 /* but some return 0 for streams too, sigh */
  309.     }
  310. #endif
  311.     }
  312.     if (saveifp) {        /* must use old fp? */
  313.     fd = fileno(saveifp);
  314.     if (saveofp) {
  315.         fflush(saveofp);        /* emulate fclose() */
  316.         if (saveofp != saveifp) {    /* was a socket? */
  317.         fclose(saveofp);
  318.         if (fd > 2)
  319.             Safefree(saveofp);
  320.         }
  321.     }
  322.     if (fd != fileno(fp)) {
  323.         int pid;
  324.         STR *str;
  325.  
  326.         dup2(fileno(fp), fd);
  327.         str = afetch(fdpid,fileno(fp),TRUE);
  328.         pid = str->str_u.str_useful;
  329.         str->str_u.str_useful = 0;
  330.         str = afetch(fdpid,fd,TRUE);
  331.         str->str_u.str_useful = pid;
  332.         fclose(fp);
  333.     }
  334.     fp = saveifp;
  335.     clearerr(fp);
  336.     }
  337. #if defined(HAS_FCNTL) && defined(F_SETFD)
  338.     fd = fileno(fp);
  339.     fcntl(fd,F_SETFD,fd > maxsysfd);
  340. #endif
  341.     stio->ifp = fp;
  342.     if (writing) {
  343.     if (stio->type == 's'
  344.       || (stio->type == '>' && S_ISCHR(statbuf.st_mode)) ) {
  345.         if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
  346.         fclose(fp);
  347.         stio->ifp = Nullfp;
  348.         goto say_false;
  349.         }
  350.     }
  351.     else
  352.         stio->ofp = fp;
  353.     }
  354.     return TRUE;
  355.  
  356. say_false:
  357.     stio->ifp = saveifp;
  358.     stio->ofp = saveofp;
  359.     stio->type = savetype;
  360.     return FALSE;
  361. }
  362.  
  363. #ifdef macintosh
  364. static FSSpec    EphTemp;
  365. static Boolean    HasEphKiller;
  366.  
  367. void EphKiller()
  368. {
  369.     if (EphTemp.name[0]) {
  370.         HDelete(EphTemp.vRefNum, EphTemp.parID, EphTemp.name);
  371.     EphTemp.name[0] = 0;
  372.     }
  373.     HasEphKiller = false;
  374. }
  375.  
  376. int Ephemeralize(char * name)
  377. {
  378.     FSSpec  old;
  379.     
  380.     if (Path2FSSpec(name, &old))
  381.         return ENOENT;
  382.     if (EphTemp.name[0] && EphTemp.vRefNum != old.vRefNum) {
  383.         HDelete(EphTemp.vRefNum, EphTemp.parID, EphTemp.name);
  384.     EphTemp.name[0] = 0;
  385.     }
  386.     if (!EphTemp.name[0] && Special2FSSpec(kTempFileType, old.vRefNum, 0, &EphTemp))
  387.         goto permErr;
  388.     
  389.     if (FSpSmartMove(&old, &EphTemp))
  390.         goto permErr;
  391.  
  392.     if (!HasEphKiller) {
  393.         atexit(EphKiller);
  394.     
  395.     HasEphKiller = true;
  396.     }
  397.  
  398.     return 0;
  399. permErr:
  400.     EphTemp.name[0] = 0;
  401.     
  402.     return EPERM;
  403. }
  404. #endif
  405.  
  406. FILE *
  407. nextargv(stab)
  408. register STAB *stab;
  409. {
  410.     register STR *str;
  411. #ifndef FLEXFILENAMES
  412.     int filedev;
  413.     int fileino;
  414. #endif
  415.     int fileuid;
  416.     int filegid;
  417.     static int lastfd;
  418.     static char *oldname;
  419.     static int filemode = 0;
  420.  
  421.     if (!argvoutstab)
  422.     argvoutstab = stabent("ARGVOUT",TRUE);
  423.     if (filemode & (S_ISUID|S_ISGID)) {
  424.     fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
  425. #ifdef HAS_FCHMOD
  426.     (void)fchmod(lastfd,filemode);
  427. #else
  428.     (void)chmod(oldname,filemode);
  429. #endif
  430.     }
  431.     filemode = 0;
  432.     while (alen(stab_xarray(stab)) >= 0) {
  433.     str = ashift(stab_xarray(stab));
  434.     str_sset(stab_val(stab),str);
  435.     STABSET(stab_val(stab));
  436.     oldname = str_get(stab_val(stab));
  437.     if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
  438.         if (inplace) {
  439. #ifdef TAINT
  440.         taintproper("Insecure dependency in inplace open");
  441. #endif
  442.         if (strEQ(oldname,"-")) {
  443.             str_free(str);
  444.             defoutstab = stabent("STDOUT",TRUE);
  445.             return stab_io(stab)->ifp;
  446.         }
  447. #ifndef FLEXFILENAMES
  448.         filedev = statbuf.st_dev;
  449.         fileino = statbuf.st_ino;
  450. #endif
  451.         filemode = statbuf.st_mode;
  452.         fileuid = statbuf.st_uid;
  453.         filegid = statbuf.st_gid;
  454.         if (!S_ISREG(filemode)) {
  455.             warn("Can't do inplace edit: %s is not a regular file",
  456.               oldname );
  457.             do_close(stab,FALSE);
  458.             str_free(str);
  459.             continue;
  460.         }
  461.         if (*inplace) {
  462. #ifdef SUFFIX
  463.             add_suffix(str,inplace);
  464. #else
  465.             str_cat(str,inplace);
  466. #endif
  467. #ifndef FLEXFILENAMES
  468.             if (stat(str->str_ptr,&statbuf) >= 0
  469.               && statbuf.st_dev == filedev
  470.               && statbuf.st_ino == fileino ) {
  471.             warn("Can't do inplace edit: %s > 14 characters",
  472.               str->str_ptr );
  473.             do_close(stab,FALSE);
  474.             str_free(str);
  475.             continue;
  476.             }
  477. #endif
  478. #ifdef HAS_RENAME
  479. #ifndef MSDOS
  480.             if (rename(oldname,str->str_ptr) < 0) {
  481.             warn("Can't rename %s to %s: %s, skipping file",
  482.               oldname, str->str_ptr, strerror(errno) );
  483.             do_close(stab,FALSE);
  484.             str_free(str);
  485.             continue;
  486.             }
  487. #else
  488.             do_close(stab,FALSE);
  489.             (void)unlink(str->str_ptr);
  490.             (void)rename(oldname,str->str_ptr);
  491.             do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
  492. #endif /* MSDOS */
  493. #else
  494.             (void)UNLINK(str->str_ptr);
  495.             if (link(oldname,str->str_ptr) < 0) {
  496.             warn("Can't rename %s to %s: %s, skipping file",
  497.               oldname, str->str_ptr, strerror(errno) );
  498.             do_close(stab,FALSE);
  499.             str_free(str);
  500.             continue;
  501.             }
  502.             (void)UNLINK(oldname);
  503. #endif
  504.         }
  505.         else {
  506. #ifndef MSMAC
  507.             if (UNLINK(oldname) < 0) {
  508.             warn("Can't rename %s to %s: %s, skipping file",
  509.               oldname, str->str_ptr, strerror(errno) );
  510.             do_close(stab,FALSE);
  511.             str_free(str);
  512.             continue;
  513.             }
  514. #else
  515. #ifdef macintosh
  516.             if (errno = Ephemeralize(oldname)) {
  517.             warn("Can't rename %s to %s: %s, skipping file",
  518.               oldname, str->str_ptr, strerror(errno) );
  519.             do_close(stab,FALSE);
  520.             str_free(str);
  521.             continue;
  522.             }
  523. #else
  524.             fatal("Can't do inplace edit without backup");
  525. #endif
  526. #endif
  527.         }
  528.  
  529.         str_nset(str,">",1);
  530.         str_cat(str,oldname);
  531.         errno = 0;        /* in case sprintf set errno */
  532.         if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
  533.             warn("Can't do inplace edit on %s: %s",
  534.               oldname, strerror(errno) );
  535.             do_close(stab,FALSE);
  536.             str_free(str);
  537.             continue;
  538.         }
  539.         defoutstab = argvoutstab;
  540.         lastfd = fileno(stab_io(argvoutstab)->ifp);
  541.         (void)fstat(lastfd,&statbuf);
  542. #ifdef HAS_FCHMOD
  543.         (void)fchmod(lastfd,filemode);
  544. #else
  545.         (void)chmod(oldname,filemode);
  546. #endif
  547.         if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
  548. #ifdef HAS_FCHOWN
  549.             (void)fchown(lastfd,fileuid,filegid);
  550. #else
  551. #ifdef HAS_CHOWN
  552.             (void)chown(oldname,fileuid,filegid);
  553. #endif
  554. #endif
  555.         }
  556.         }
  557.         str_free(str);
  558.         return stab_io(stab)->ifp;
  559.     }
  560.     else
  561. #ifdef macintosh
  562.         fprintf(stderr,"# Can't open %s: %s\n",str_get(str), strerror(errno));
  563. #else
  564.         fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
  565. #endif
  566.     str_free(str);
  567.     }
  568.     if (inplace) {
  569.     (void)do_close(argvoutstab,FALSE);
  570.     defoutstab = stabent("STDOUT",TRUE);
  571.     }
  572.     return Nullfp;
  573. }
  574.  
  575. #ifdef HAS_PIPE 
  576. void
  577. do_pipe(str, rstab, wstab)
  578. STR *str;
  579. STAB *rstab;
  580. STAB *wstab;
  581. {
  582.     register STIO *rstio;
  583.     register STIO *wstio;
  584.     int fd[2];
  585.  
  586.     if (!rstab)
  587.     goto badexit;
  588.     if (!wstab)
  589.     goto badexit;
  590.  
  591.     rstio = stab_io(rstab);
  592.     wstio = stab_io(wstab);
  593.  
  594.     if (!rstio)
  595.     rstio = stab_io(rstab) = stio_new();
  596.     else if (rstio->ifp)
  597.     do_close(rstab,FALSE);
  598.     if (!wstio)
  599.     wstio = stab_io(wstab) = stio_new();
  600.     else if (wstio->ifp)
  601.     do_close(wstab,FALSE);
  602.  
  603.     if (pipe(fd) < 0)
  604.     goto badexit;
  605.     rstio->ifp = fdopen(fd[0], "r");
  606.     wstio->ofp = fdopen(fd[1], "w");
  607.     wstio->ifp = wstio->ofp;
  608.     rstio->type = '<';
  609.     wstio->type = '>';
  610.     if (!rstio->ifp || !wstio->ofp) {
  611.     if (rstio->ifp) fclose(rstio->ifp);
  612.     else close(fd[0]);
  613.     if (wstio->ofp) fclose(wstio->ofp);
  614.     else close(fd[1]);
  615.     goto badexit;
  616.     }
  617.  
  618.     str_sset(str,&str_yes);
  619.     return;
  620.  
  621. badexit:
  622.     str_sset(str,&str_undef);
  623.     return;
  624. }
  625. #endif
  626.  
  627. bool
  628. do_close(stab,explicit)
  629. STAB *stab;
  630. bool explicit;
  631. {
  632.     bool retval = FALSE;
  633.     register STIO *stio;
  634.     int status;
  635.  
  636.     if (!stab)
  637.     stab = argvstab;
  638.     if (!stab) {
  639.     errno = EBADF;
  640.     return FALSE;
  641.     }
  642.     stio = stab_io(stab);
  643.     if (!stio) {        /* never opened */
  644.     if (dowarn && explicit)
  645.         warn("Close on unopened file <%s>",stab_ename(stab));
  646.     return FALSE;
  647.     }
  648.     if (stio->ifp) {
  649.     if (stio->type == '|') {
  650.         status = mypclose(stio->ifp);
  651.         retval = (status == 0);
  652.         statusvalue = (unsigned short)status & 0xffff;
  653.     }
  654.     else if (stio->type == '-')
  655.         retval = TRUE;
  656.     else {
  657.         if (stio->ofp && stio->ofp != stio->ifp) {        /* a socket */
  658.         retval = (fclose(stio->ofp) != EOF);
  659.         fclose(stio->ifp);    /* clear stdio, fd already closed */
  660.         }
  661.         else
  662.         retval = (fclose(stio->ifp) != EOF);
  663.     }
  664.     stio->ofp = stio->ifp = Nullfp;
  665.     }
  666.     if (explicit)
  667.     stio->lines = 0;
  668.     stio->type = ' ';
  669.     return retval;
  670. }
  671.  
  672. bool
  673. do_eof(stab)
  674. STAB *stab;
  675. {
  676.     register STIO *stio;
  677.     int ch;
  678.  
  679.     if (!stab) {            /* eof() */
  680.     if (argvstab)
  681.         stio = stab_io(argvstab);
  682.     else
  683.         return TRUE;
  684.     }
  685.     else
  686.     stio = stab_io(stab);
  687.  
  688.     if (!stio)
  689.     return TRUE;
  690.  
  691.     while (stio->ifp) {
  692.  
  693. #ifdef STDSTDIO            /* (the code works without this) */
  694.     if (stio->ifp->_cnt > 0)    /* cheat a little, since */
  695.         return FALSE;        /* this is the most usual case */
  696. #endif
  697.  
  698.     ch = getc(stio->ifp);
  699.     if (ch != EOF) {
  700.         (void)ungetc(ch, stio->ifp);
  701.         return FALSE;
  702.     }
  703. #ifdef STDSTDIO
  704.     if (stio->ifp->_cnt < -1)
  705.         stio->ifp->_cnt = -1;
  706. #endif
  707.     if (!stab) {            /* not necessarily a real EOF yet? */
  708.         if (!nextargv(argvstab))    /* get another fp handy */
  709.         return TRUE;
  710.     }
  711.     else
  712.         return TRUE;        /* normal fp, definitely end of file */
  713.     }
  714.     return TRUE;
  715. }
  716.  
  717. long
  718. do_tell(stab)
  719. STAB *stab;
  720. {
  721.     register STIO *stio;
  722.  
  723.     if (!stab)
  724.     goto phooey;
  725.  
  726.     stio = stab_io(stab);
  727.     if (!stio || !stio->ifp)
  728.     goto phooey;
  729.  
  730. #ifdef ULTRIX_STDIO_BOTCH
  731.     if (feof(stio->ifp))
  732.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  733. #endif
  734.  
  735.     return ftell(stio->ifp);
  736.  
  737. phooey:
  738.     if (dowarn)
  739.     warn("tell() on unopened file");
  740.     errno = EBADF;
  741.     return -1L;
  742. }
  743.  
  744. bool
  745. do_seek(stab, pos, whence)
  746. STAB *stab;
  747. long pos;
  748. int whence;
  749. {
  750.     register STIO *stio;
  751.  
  752.     if (!stab)
  753.     goto nuts;
  754.  
  755.     stio = stab_io(stab);
  756.     if (!stio || !stio->ifp)
  757.     goto nuts;
  758.  
  759. #ifdef ULTRIX_STDIO_BOTCH
  760.     if (feof(stio->ifp))
  761.     (void)fseek (stio->ifp, 0L, 2);        /* ultrix 1.2 workaround */
  762. #endif
  763.  
  764.     return fseek(stio->ifp, pos, whence) >= 0;
  765.  
  766. nuts:
  767.     if (dowarn)
  768.     warn("seek() on unopened file");
  769.     errno = EBADF;
  770.     return FALSE;
  771. }
  772.  
  773. int
  774. do_ctl(optype,stab,func,argstr)
  775. int optype;
  776. STAB *stab;
  777. int func;
  778. STR *argstr;
  779. {
  780.     register STIO *stio;
  781.     register char *s;
  782.     int retval;
  783.  
  784.     if (!stab || !argstr || !(stio = stab_io(stab)) || !stio->ifp) {
  785.     errno = EBADF;    /* well, sort of... */
  786.     return -1;
  787.     }
  788.  
  789.     if (argstr->str_pok || !argstr->str_nok) {
  790.     if (!argstr->str_pok)
  791.         s = str_get(argstr);
  792.  
  793. #ifdef IOCPARM_MASK
  794. #ifndef IOCPARM_LEN
  795. #define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
  796. #endif
  797. #endif
  798. #ifdef IOCPARM_LEN
  799.     retval = IOCPARM_LEN(func);    /* on BSDish systes we're safe */
  800. #else
  801.     retval = 256;            /* otherwise guess at what's safe */
  802. #endif
  803.     if (argstr->str_cur < retval) {
  804.         Str_Grow(argstr,retval+1);
  805.         argstr->str_cur = retval;
  806.     }
  807.  
  808.     s = argstr->str_ptr;
  809.     s[argstr->str_cur] = 17;    /* a little sanity check here */
  810.     }
  811.     else {
  812.     retval = (int)str_gnum(argstr);
  813. #ifdef DOSISH
  814.     s = (char*)(long)retval;        /* ouch */
  815. #else
  816.     s = (char*)retval;        /* ouch */
  817. #endif
  818.     }
  819.  
  820. #ifndef lint
  821.     if (optype == O_IOCTL)
  822. #ifdef macintosh
  823.     retval = ioctl(fileno(stio->ifp), func, (long *) s);
  824. #else
  825.     retval = ioctl(fileno(stio->ifp), func, s);
  826. #endif
  827.     else
  828. #ifdef DOSISH
  829.     fatal("fcntl is not implemented");
  830. #else
  831. #ifdef macintosh
  832.     retval = fcntl(fileno(stio->ifp), func, (int) s);
  833. #else
  834. #ifdef HAS_FCNTL
  835.     retval = fcntl(fileno(stio->ifp), func, s);
  836. #else
  837.     fatal("fcntl is not implemented");
  838. #endif
  839. #endif
  840. #endif
  841. #else /* lint */
  842.     retval = 0;
  843. #endif /* lint */
  844.  
  845.     if (argstr->str_pok) {
  846.     if (s[argstr->str_cur] != 17)
  847.         fatal("Return value overflowed string");
  848.     s[argstr->str_cur] = 0;        /* put our null back */
  849.     }
  850.     return retval;
  851. }
  852.  
  853. int
  854. do_stat(str,arg,gimme,arglast)
  855. STR *str;
  856. register ARG *arg;
  857. int gimme;
  858. int *arglast;
  859. {
  860.     register ARRAY *ary = stack;
  861.     register int sp = arglast[0] + 1;
  862.     int max = 13;
  863.  
  864.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  865.     tmpstab = arg[1].arg_ptr.arg_stab;
  866.     if (tmpstab != defstab) {
  867.         laststype = O_STAT;
  868.         statstab = tmpstab;
  869.         str_set(statname,"");
  870.         if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  871.           fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
  872.         max = 0;
  873.         laststatval = -1;
  874.         }
  875.     }
  876.     else if (laststatval < 0)
  877.         max = 0;
  878.     }
  879.     else {
  880.     str_set(statname,str_get(ary->ary_array[sp]));
  881.     statstab = Nullstab;
  882. #ifdef HAS_LSTAT
  883.     laststype = arg->arg_type;
  884.     if (arg->arg_type == O_LSTAT)
  885.         laststatval = lstat(str_get(statname),&statcache);
  886.     else
  887. #endif
  888.         laststatval = stat(str_get(statname),&statcache);
  889.     if (laststatval < 0) {
  890.         if (dowarn && index(str_get(statname), '\n'))
  891.         warn(warn_nl, "stat");
  892.         max = 0;
  893.     }
  894.     }
  895.  
  896.     if (gimme != G_ARRAY) {
  897.     if (max)
  898.         str_sset(str,&str_yes);
  899.     else
  900.         str_sset(str,&str_undef);
  901.     STABSET(str);
  902.     ary->ary_array[sp] = str;
  903.     return sp;
  904.     }
  905.     sp--;
  906.     if (max) {
  907. #ifndef lint
  908.     (void)astore(ary,++sp,
  909.       str_2mortal(str_nmake((double)statcache.st_dev)));
  910.     (void)astore(ary,++sp,
  911.       str_2mortal(str_nmake((double)statcache.st_ino)));
  912.     (void)astore(ary,++sp,
  913.       str_2mortal(str_nmake((double)statcache.st_mode)));
  914.     (void)astore(ary,++sp,
  915.       str_2mortal(str_nmake((double)statcache.st_nlink)));
  916.     (void)astore(ary,++sp,
  917.       str_2mortal(str_nmake((double)statcache.st_uid)));
  918.     (void)astore(ary,++sp,
  919.       str_2mortal(str_nmake((double)statcache.st_gid)));
  920.     (void)astore(ary,++sp,
  921.       str_2mortal(str_nmake((double)statcache.st_rdev)));
  922.     (void)astore(ary,++sp,
  923.       str_2mortal(str_nmake((double)statcache.st_size)));
  924.     (void)astore(ary,++sp,
  925.       str_2mortal(str_nmake((double)statcache.st_atime)));
  926.     (void)astore(ary,++sp,
  927.       str_2mortal(str_nmake((double)statcache.st_mtime)));
  928.     (void)astore(ary,++sp,
  929.       str_2mortal(str_nmake((double)statcache.st_ctime)));
  930. #ifdef STATBLOCKS
  931.     (void)astore(ary,++sp,
  932.       str_2mortal(str_nmake((double)statcache.st_blksize)));
  933.     (void)astore(ary,++sp,
  934.       str_2mortal(str_nmake((double)statcache.st_blocks)));
  935. #else
  936.     (void)astore(ary,++sp,
  937.       str_2mortal(str_make("",0)));
  938.     (void)astore(ary,++sp,
  939.       str_2mortal(str_make("",0)));
  940. #endif
  941. #else /* lint */
  942.     (void)astore(ary,++sp,str_nmake(0.0));
  943. #endif /* lint */
  944.     }
  945.     return sp;
  946. }
  947.  
  948. #if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
  949.     /* code courtesy of William Kucharski */
  950. #define HAS_CHSIZE
  951.  
  952. int chsize(fd, length)
  953. int fd;            /* file descriptor */
  954. off_t length;        /* length to set file to */
  955. {
  956.     extern long lseek();
  957.     struct flock fl;
  958.     struct stat filebuf;
  959.  
  960.     if (fstat(fd, &filebuf) < 0)
  961.     return -1;
  962.  
  963.     if (filebuf.st_size < length) {
  964.  
  965.     /* extend file length */
  966.  
  967.     if ((lseek(fd, (length - 1), 0)) < 0)
  968.         return -1;
  969.  
  970.     /* write a "0" byte */
  971.  
  972.     if ((write(fd, "", 1)) != 1)
  973.         return -1;
  974.     }
  975.     else {
  976.     /* truncate length */
  977.  
  978.     fl.l_whence = 0;
  979.     fl.l_len = 0;
  980.     fl.l_start = length;
  981.     fl.l_type = F_WRLCK;    /* write lock on file space */
  982.  
  983.     /*
  984.     * This relies on the UNDOCUMENTED F_FREESP argument to
  985.     * fcntl(2), which truncates the file so that it ends at the
  986.     * position indicated by fl.l_start.
  987.     *
  988.     * Will minor miracles never cease?
  989.     */
  990.  
  991.     if (fcntl(fd, F_FREESP, &fl) < 0)
  992.         return -1;
  993.  
  994.     }
  995.  
  996.     return 0;
  997. }
  998. #endif /* F_FREESP */
  999.  
  1000. int                    /*SUPPRESS 590*/
  1001. do_truncate(str,arg,gimme,arglast)
  1002. STR *str;
  1003. register ARG *arg;
  1004. int gimme;
  1005. int *arglast;
  1006. {
  1007.     register ARRAY *ary = stack;
  1008.     register int sp = arglast[0] + 1;
  1009.     off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
  1010.     int result = 1;
  1011.     STAB *tmpstab;
  1012.  
  1013. #if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
  1014. #ifdef HAS_TRUNCATE
  1015.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  1016.     tmpstab = arg[1].arg_ptr.arg_stab;
  1017.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  1018.       ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
  1019.         result = 0;
  1020.     }
  1021.     else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
  1022.     result = 0;
  1023. #else
  1024.     if ((arg[1].arg_type & A_MASK) == A_WORD) {
  1025.     tmpstab = arg[1].arg_ptr.arg_stab;
  1026.     if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
  1027.       chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
  1028.         result = 0;
  1029.     }
  1030.     else {
  1031.     int tmpfd;
  1032.  
  1033.     if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
  1034.         result = 0;
  1035.     else {
  1036.         if (chsize(tmpfd, len) < 0)
  1037.         result = 0;
  1038.         close(tmpfd);
  1039.     }
  1040.     }
  1041. #endif
  1042.  
  1043.     if (result)
  1044.     str_sset(str,&str_yes);
  1045.     else
  1046.     str_sset(str,&str_undef);
  1047.     STABSET(str);
  1048.     ary->ary_array[sp] = str;
  1049.     return sp;
  1050. #else
  1051.     fatal("truncate not implemented");
  1052. #endif
  1053. }
  1054.  
  1055. int
  1056. looks_like_number(str)
  1057. STR *str;
  1058. {
  1059.     register char *s;
  1060.     register char *send;
  1061.  
  1062.     if (!str->str_pok)
  1063.     return TRUE;
  1064.     s = str->str_ptr; 
  1065.     send = s + str->str_cur;
  1066.     while (isSPACE(*s))
  1067.     s++;
  1068.     if (s >= send)
  1069.     return FALSE;
  1070.     if (*s == '+' || *s == '-')
  1071.     s++;
  1072.     while (isDIGIT(*s))
  1073.     s++;
  1074.     if (s == send)
  1075.     return TRUE;
  1076.     if (*s == '.') 
  1077.     s++;
  1078.     else if (s == str->str_ptr)
  1079.     return FALSE;
  1080.     while (isDIGIT(*s))
  1081.     s++;
  1082.     if (s == send)
  1083.     return TRUE;
  1084.     if (*s == 'e' || *s == 'E') {
  1085.     s++;
  1086.     if (*s == '+' || *s == '-')
  1087.         s++;
  1088.     while (isDIGIT(*s))
  1089.         s++;
  1090.     }
  1091.     while (isSPACE(*s))
  1092.     s++;
  1093.     if (s >= send)
  1094.     return TRUE;
  1095.     return FALSE;
  1096. }
  1097.  
  1098. bool
  1099. do_print(str,fp)
  1100. register STR *str;
  1101. FILE *fp;
  1102. {
  1103.     register char *tmps;
  1104.  
  1105.     if (!fp) {
  1106.     if (dowarn)
  1107.         warn("print to unopened file");
  1108.     errno = EBADF;
  1109.     return FALSE;
  1110.     }
  1111.     if (!str)
  1112.     return TRUE;
  1113.     if (ofmt &&
  1114.       ((str->str_nok && str->str_u.str_nval != 0.0)
  1115.        || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
  1116.     fprintf(fp, ofmt, str->str_u.str_nval);
  1117.     return !ferror(fp);
  1118.     }
  1119.     else {
  1120.     tmps = str_get(str);
  1121.     if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
  1122.       && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
  1123.         STR *tmpstr = str_mortal(&str_undef);
  1124.         stab_efullname(tmpstr,((STAB*)str));/* a stab value, be nice */
  1125.         str = tmpstr;
  1126.         tmps = str->str_ptr;
  1127.         putc('*',fp);
  1128.     }
  1129.     if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
  1130.         return FALSE;
  1131.     }
  1132.     return TRUE;
  1133. }
  1134.  
  1135. bool
  1136. do_aprint(arg,fp,arglast)
  1137. register ARG *arg;
  1138. register FILE *fp;
  1139. int *arglast;
  1140. {
  1141.     register STR **st = stack->ary_array;
  1142.     register int sp = arglast[1];
  1143.     register int retval;
  1144.     register int items = arglast[2] - sp;
  1145.  
  1146.     if (!fp) {
  1147.     if (dowarn)
  1148.         warn("print to unopened file");
  1149.     errno = EBADF;
  1150.     return FALSE;
  1151.     }
  1152.     st += ++sp;
  1153.     if (arg->arg_type == O_PRTF) {
  1154.     do_sprintf(arg->arg_ptr.arg_str,items,st);
  1155.     retval = do_print(arg->arg_ptr.arg_str,fp);
  1156.     }
  1157.     else {
  1158.     retval = (items <= 0);
  1159.     for (; items > 0; items--,st++) {
  1160.         if (retval && ofslen) {
  1161.         if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
  1162.             retval = FALSE;
  1163.             break;
  1164.         }
  1165.         }
  1166.         if (!(retval = do_print(*st, fp)))
  1167.         break;
  1168.     }
  1169.     if (retval && orslen)
  1170.         if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
  1171.         retval = FALSE;
  1172.     }
  1173.     return retval;
  1174. }
  1175.  
  1176. int
  1177. mystat(arg,str)
  1178. ARG *arg;
  1179. STR *str;
  1180. {
  1181.     STIO *stio;
  1182.  
  1183.     if (arg[1].arg_type & A_DONT) {
  1184.     stio = stab_io(arg[1].arg_ptr.arg_stab);
  1185.     if (stio && stio->ifp) {
  1186.         statstab = arg[1].arg_ptr.arg_stab;
  1187.         str_set(statname,"");
  1188.         laststype = O_STAT;
  1189.         return (laststatval = fstat(fileno(stio->ifp), &statcache));
  1190.     }
  1191.     else {
  1192.         if (arg[1].arg_ptr.arg_stab == defstab)
  1193.         return laststatval;
  1194.         if (dowarn)
  1195.         warn("Stat on unopened file <%s>",
  1196.           stab_ename(arg[1].arg_ptr.arg_stab));
  1197.         statstab = Nullstab;
  1198.         str_set(statname,"");
  1199.         return (laststatval = -1);
  1200.     }
  1201.     }
  1202.     else {
  1203.     statstab = Nullstab;
  1204.     str_set(statname,str_get(str));
  1205.     laststype = O_STAT;
  1206.     laststatval = stat(str_get(str),&statcache);
  1207.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1208.         warn(warn_nl, "stat");
  1209.     return laststatval;
  1210.     }
  1211. }
  1212.  
  1213. int
  1214. mylstat(arg,str)
  1215. ARG *arg;
  1216. STR *str;
  1217. {
  1218.     if (arg[1].arg_type & A_DONT) {
  1219.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1220.         if (laststype != O_LSTAT)
  1221.         fatal("The stat preceding -l _ wasn't an lstat");
  1222.         return laststatval;
  1223.     }
  1224.     fatal("You can't use -l on a filehandle");
  1225.     }
  1226.  
  1227.     laststype = O_LSTAT;
  1228.     statstab = Nullstab;
  1229.     str_set(statname,str_get(str));
  1230. #ifdef HAS_LSTAT
  1231.     laststatval = lstat(str_get(str),&statcache);
  1232. #else
  1233.     laststatval = stat(str_get(str),&statcache);
  1234. #endif
  1235.     if (laststatval < 0 && dowarn && index(str_get(str), '\n'))
  1236.     warn(warn_nl, "lstat");
  1237.     return laststatval;
  1238. }
  1239.  
  1240. STR *
  1241. do_fttext(arg,str)
  1242. register ARG *arg;
  1243. STR *str;
  1244. {
  1245.     int i;
  1246.     int len;
  1247.     int odd = 0;
  1248.     STDCHAR tbuf[512];
  1249.     register STDCHAR *s;
  1250.     register STIO *stio;
  1251.  
  1252.     if (arg[1].arg_type & A_DONT) {
  1253.     if (arg[1].arg_ptr.arg_stab == defstab) {
  1254.         if (statstab)
  1255.         stio = stab_io(statstab);
  1256.         else {
  1257.         str = statname;
  1258.         goto really_filename;
  1259.         }
  1260.     }
  1261.     else {
  1262.         statstab = arg[1].arg_ptr.arg_stab;
  1263.         str_set(statname,"");
  1264.         stio = stab_io(statstab);
  1265.     }
  1266.     if (stio && stio->ifp) {
  1267. #if defined(STDSTDIO) || defined(atarist) /* this will work with atariST */
  1268.         fstat(fileno(stio->ifp),&statcache);
  1269.         if (S_ISDIR(statcache.st_mode))    /* handle NFS glitch */
  1270.         return arg->arg_type == O_FTTEXT ? &str_no : &str_yes;
  1271.         if (stio->ifp->_cnt <= 0) {
  1272.         i = getc(stio->ifp);
  1273.         if (i != EOF)
  1274.             (void)ungetc(i,stio->ifp);
  1275.         }
  1276.         if (stio->ifp->_cnt <= 0)    /* null file is anything */
  1277.         return &str_yes;
  1278.         len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
  1279.         s = stio->ifp->_base;
  1280. #else
  1281.         fatal("-T and -B not implemented on filehandles");
  1282. #endif
  1283.     }
  1284.     else {
  1285.         if (dowarn)
  1286.         warn("Test on unopened file <%s>",
  1287.           stab_ename(arg[1].arg_ptr.arg_stab));
  1288.         errno = EBADF;
  1289.         return &str_undef;
  1290.     }
  1291.     }
  1292.     else {
  1293.     statstab = Nullstab;
  1294.     str_set(statname,str_get(str));
  1295.       really_filename:
  1296.     i = open(str_get(str),0);
  1297.     if (i < 0) {
  1298.         if (dowarn && index(str_get(str), '\n'))
  1299.         warn(warn_nl, "open");
  1300.         return &str_undef;
  1301.     }
  1302.     fstat(i,&statcache);
  1303.     len = read(i,tbuf,512);
  1304.     (void)close(i);
  1305.     if (len <= 0) {
  1306.         if (S_ISDIR(statcache.st_mode) && arg->arg_type == O_FTTEXT)
  1307.         return &str_no;        /* special case NFS directories */
  1308.         return &str_yes;        /* null file is anything */
  1309.     }
  1310.     s = tbuf;
  1311.     }
  1312.  
  1313.     /* now scan s to look for textiness */
  1314.  
  1315.     for (i = 0; i < len; i++,s++) {
  1316.     if (!*s) {            /* null never allowed in text */
  1317.         odd += len;
  1318.         break;
  1319.     }
  1320.     else if (*s & 128)
  1321.         odd++;
  1322.     else if (*s < 32 &&
  1323.       *s != '\n' && *s != '\r' && *s != '\b' &&
  1324.       *s != '\t' && *s != '\f' && *s != 27)
  1325.         odd++;
  1326.     }
  1327.  
  1328.     if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
  1329.     return &str_no;
  1330.     else
  1331.     return &str_yes;
  1332. }
  1333.  
  1334. static char **Argv = Null(char **);
  1335. static char *Cmd = Nullch;
  1336.  
  1337. bool
  1338. do_aexec(really,arglast)
  1339. STR *really;
  1340. int *arglast;
  1341. {
  1342.     register STR **st = stack->ary_array;
  1343.     register int sp = arglast[1];
  1344.     register int items = arglast[2] - sp;
  1345.     register char **a;
  1346.     char *tmps;
  1347.  
  1348.     if (items) {
  1349.     New(401,Argv, items+1, char*);
  1350.     a = Argv;
  1351.     for (st += ++sp; items > 0; items--,st++) {
  1352.         if (*st)
  1353.         *a++ = str_get(*st);
  1354.         else
  1355.         *a++ = "";
  1356.     }
  1357.     *a = Nullch;
  1358. #ifdef TAINT
  1359.     if (*Argv[0] != '/')    /* will execvp use PATH? */
  1360.         taintenv();        /* testing IFS here is overkill, probably */
  1361. #endif
  1362.     if (really && *(tmps = str_get(really)))
  1363.         execvp(tmps,Argv);
  1364.     else
  1365.         execvp(Argv[0],Argv);
  1366.     }
  1367.     do_execfree();
  1368.     return FALSE;
  1369. }
  1370.  
  1371. void
  1372. do_execfree()
  1373. {
  1374.     if (Argv) {
  1375.     Safefree(Argv);
  1376.     Argv = Null(char **);
  1377.     }
  1378.     if (Cmd) {
  1379.     Safefree(Cmd);
  1380.     Cmd = Nullch;
  1381.     }
  1382. }
  1383.  
  1384. bool
  1385. do_exec(cmd)
  1386. char *cmd;
  1387. {
  1388. #ifdef macintosh
  1389.     fatal("exec() on a mac ? You gotta be joking !");
  1390. #else
  1391.     register char **a;
  1392.     register char *s;
  1393.     char flags[10];
  1394.  
  1395.     /* save an extra exec if possible */
  1396.  
  1397. #ifdef CSH
  1398.     if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
  1399.     strcpy(flags,"-c");
  1400.     s = cmd+cshlen+3;
  1401.     if (*s == 'f') {
  1402.         s++;
  1403.         strcat(flags,"f");
  1404.     }
  1405.     if (*s == ' ')
  1406.         s++;
  1407.     if (*s++ == '\'') {
  1408.         char *ncmd = s;
  1409.  
  1410.         while (*s)
  1411.         s++;
  1412.         if (s[-1] == '\n')
  1413.         *--s = '\0';
  1414.         if (s[-1] == '\'') {
  1415.         *--s = '\0';
  1416.         execl(cshname,"csh", flags,ncmd,(char*)0);
  1417.         *s = '\'';
  1418.         return FALSE;
  1419.         }
  1420.     }
  1421.     }
  1422. #endif /* CSH */
  1423.  
  1424.     /* see if there are shell metacharacters in it */
  1425.  
  1426.     /*SUPPRESS 530*/
  1427.     for (s = cmd; *s && isALPHA(*s); s++) ;    /* catch VAR=val gizmo */
  1428.     if (*s == '=')
  1429.     goto doshell;
  1430.     for (s = cmd; *s; s++) {
  1431.     if (*s != ' ' && !isALPHA(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
  1432.         if (*s == '\n' && !s[1]) {
  1433.         *s = '\0';
  1434.         break;
  1435.         }
  1436.       doshell:
  1437.         execl("/bin/sh","sh","-c",cmd,(char*)0);
  1438.         return FALSE;
  1439.     }
  1440.     }
  1441.     New(402,Argv, (s - cmd) / 2 + 2, char*);
  1442.     Cmd = nsavestr(cmd, s-cmd);
  1443.     a = Argv;
  1444.     for (s = Cmd; *s;) {
  1445.     while (*s && isSPACE(*s)) s++;
  1446.     if (*s)
  1447.         *(a++) = s;
  1448.     while (*s && !isSPACE(*s)) s++;
  1449.     if (*s)
  1450.         *s++ = '\0';
  1451.     }
  1452.     *a = Nullch;
  1453.     if (Argv[0]) {
  1454.     execvp(Argv[0],Argv);
  1455.     if (errno == ENOEXEC) {        /* for system V NIH syndrome */
  1456.         do_execfree();
  1457.         goto doshell;
  1458.     }
  1459.     }
  1460.     do_execfree();
  1461.     return FALSE;
  1462. #endif
  1463. }
  1464.  
  1465. #ifdef HAS_SOCKET
  1466. int
  1467. do_socket(stab, arglast)
  1468. STAB *stab;
  1469. int *arglast;
  1470. {
  1471.     register STR **st = stack->ary_array;
  1472.     register int sp = arglast[1];
  1473.     register STIO *stio;
  1474.     int domain, type, protocol, fd;
  1475.  
  1476.     if (!stab) {
  1477.     errno = EBADF;
  1478.     return FALSE;
  1479.     }
  1480.  
  1481.     stio = stab_io(stab);
  1482.     if (!stio)
  1483.     stio = stab_io(stab) = stio_new();
  1484.     else if (stio->ifp)
  1485.     do_close(stab,FALSE);
  1486.  
  1487.     domain = (int)str_gnum(st[++sp]);
  1488.     type = (int)str_gnum(st[++sp]);
  1489.     protocol = (int)str_gnum(st[++sp]);
  1490. #ifdef TAINT
  1491.     taintproper("Insecure dependency in socket");
  1492. #endif
  1493.     fd = socket(domain,type,protocol);
  1494.     if (fd < 0)
  1495.     return FALSE;
  1496.     stio->ifp = fdopen(fd, "r");    /* stdio gets confused about sockets */
  1497.     stio->ofp = fdopen(fd, "w");
  1498.     stio->type = 's';
  1499.     if (!stio->ifp || !stio->ofp) {
  1500.     if (stio->ifp) fclose(stio->ifp);
  1501.     if (stio->ofp) fclose(stio->ofp);
  1502.     if (!stio->ifp && !stio->ofp) close(fd);
  1503.     return FALSE;
  1504.     }
  1505.  
  1506.     return TRUE;
  1507. }
  1508.  
  1509. int
  1510. do_bind(stab, arglast)
  1511. STAB *stab;
  1512. int *arglast;
  1513. {
  1514.     register STR **st = stack->ary_array;
  1515.     register int sp = arglast[1];
  1516.     register STIO *stio;
  1517.     char *addr;
  1518.  
  1519.     if (!stab)
  1520.     goto nuts;
  1521.  
  1522.     stio = stab_io(stab);
  1523.     if (!stio || !stio->ifp)
  1524.     goto nuts;
  1525.  
  1526.     addr = str_get(st[++sp]);
  1527. #ifdef TAINT
  1528.     taintproper("Insecure dependency in bind");
  1529. #endif
  1530. #ifdef macintosh
  1531.     return bind(fileno(stio->ifp), (struct sockaddr *) addr, st[sp]->str_cur) >= 0;
  1532. #else
  1533.     return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1534. #endif
  1535.  
  1536. nuts:
  1537.     if (dowarn)
  1538.     warn("bind() on closed fd");
  1539.     errno = EBADF;
  1540.     return FALSE;
  1541.  
  1542. }
  1543.  
  1544. int
  1545. do_connect(stab, arglast)
  1546. STAB *stab;
  1547. int *arglast;
  1548. {
  1549.     register STR **st = stack->ary_array;
  1550.     register int sp = arglast[1];
  1551.     register STIO *stio;
  1552.     char *addr;
  1553.  
  1554.     if (!stab)
  1555.     goto nuts;
  1556.  
  1557.     stio = stab_io(stab);
  1558.     if (!stio || !stio->ifp)
  1559.     goto nuts;
  1560.  
  1561.     addr = str_get(st[++sp]);
  1562. #ifdef TAINT
  1563.     taintproper("Insecure dependency in connect");
  1564. #endif
  1565. #ifdef macintosh
  1566.     return connect(fileno(stio->ifp), (struct sockaddr *) addr, st[sp]->str_cur) >= 0;
  1567. #else
  1568.     return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
  1569. #endif
  1570.  
  1571. nuts:
  1572.     if (dowarn)
  1573.     warn("connect() on closed fd");
  1574.     errno = EBADF;
  1575.     return FALSE;
  1576.  
  1577. }
  1578.  
  1579. int
  1580. do_listen(stab, arglast)
  1581. STAB *stab;
  1582. int *arglast;
  1583. {
  1584.     register STR **st = stack->ary_array;
  1585.     register int sp = arglast[1];
  1586.     register STIO *stio;
  1587.     int backlog;
  1588.  
  1589.     if (!stab)
  1590.     goto nuts;
  1591.  
  1592.     stio = stab_io(stab);
  1593.     if (!stio || !stio->ifp)
  1594.     goto nuts;
  1595.  
  1596.     backlog = (int)str_gnum(st[++sp]);
  1597.     return listen(fileno(stio->ifp), backlog) >= 0;
  1598.  
  1599. nuts:
  1600.     if (dowarn)
  1601.     warn("listen() on closed fd");
  1602.     errno = EBADF;
  1603.     return FALSE;
  1604. }
  1605.  
  1606. void
  1607. do_accept(str, nstab, gstab)
  1608. STR *str;
  1609. STAB *nstab;
  1610. STAB *gstab;
  1611. {
  1612.     register STIO *nstio;
  1613.     register STIO *gstio;
  1614.     int len = sizeof buf;
  1615.     int fd;
  1616.  
  1617.     if (!nstab)
  1618.     goto badexit;
  1619.     if (!gstab)
  1620.     goto nuts;
  1621.  
  1622.     gstio = stab_io(gstab);
  1623.     nstio = stab_io(nstab);
  1624.  
  1625.     if (!gstio || !gstio->ifp)
  1626.     goto nuts;
  1627.     if (!nstio)
  1628.     nstio = stab_io(nstab) = stio_new();
  1629.     else if (nstio->ifp)
  1630.     do_close(nstab,FALSE);
  1631.  
  1632.     fd = accept(fileno(gstio->ifp),(struct sockaddr *)buf,&len);
  1633.     if (fd < 0)
  1634.     goto badexit;
  1635.     nstio->ifp = fdopen(fd, "r");
  1636.     nstio->ofp = fdopen(fd, "w");
  1637.     nstio->type = 's';
  1638.     if (!nstio->ifp || !nstio->ofp) {
  1639.     if (nstio->ifp) fclose(nstio->ifp);
  1640.     if (nstio->ofp) fclose(nstio->ofp);
  1641.     if (!nstio->ifp && !nstio->ofp) close(fd);
  1642.     goto badexit;
  1643.     }
  1644.  
  1645.     str_nset(str, buf, len);
  1646.     return;
  1647.  
  1648. nuts:
  1649.     if (dowarn)
  1650.     warn("accept() on closed fd");
  1651.     errno = EBADF;
  1652. badexit:
  1653.     str_sset(str,&str_undef);
  1654.     return;
  1655. }
  1656.  
  1657. int
  1658. do_shutdown(stab, arglast)
  1659. STAB *stab;
  1660. int *arglast;
  1661. {
  1662.     register STR **st = stack->ary_array;
  1663.     register int sp = arglast[1];
  1664.     register STIO *stio;
  1665.     int how;
  1666.  
  1667.     if (!stab)
  1668.     goto nuts;
  1669.  
  1670.     stio = stab_io(stab);
  1671.     if (!stio || !stio->ifp)
  1672.     goto nuts;
  1673.  
  1674.     how = (int)str_gnum(st[++sp]);
  1675.     return shutdown(fileno(stio->ifp), how) >= 0;
  1676.  
  1677. nuts:
  1678.     if (dowarn)
  1679.     warn("shutdown() on closed fd");
  1680.     errno = EBADF;
  1681.     return FALSE;
  1682.  
  1683. }
  1684.  
  1685. int
  1686. do_sopt(optype, stab, arglast)
  1687. int optype;
  1688. STAB *stab;
  1689. int *arglast;
  1690. {
  1691.     register STR **st = stack->ary_array;
  1692.     register int sp = arglast[1];
  1693.     register STIO *stio;
  1694.     int fd;
  1695.     unsigned int lvl;
  1696.     unsigned int optname;
  1697.  
  1698.     if (!stab)
  1699.     goto nuts;
  1700.  
  1701.     stio = stab_io(stab);
  1702.     if (!stio || !stio->ifp)
  1703.     goto nuts;
  1704.  
  1705.     fd = fileno(stio->ifp);
  1706.     lvl = (unsigned int)str_gnum(st[sp+1]);
  1707.     optname = (unsigned int)str_gnum(st[sp+2]);
  1708.     switch (optype) {
  1709.     case O_GSOCKOPT:
  1710.     st[sp] = str_2mortal(Str_new(22,257));
  1711.     st[sp]->str_cur = 256;
  1712.     st[sp]->str_pok = 1;
  1713.     if (getsockopt(fd, lvl, optname, st[sp]->str_ptr,
  1714.             (int*)&st[sp]->str_cur) < 0)
  1715.         goto nuts;
  1716.     break;
  1717.     case O_SSOCKOPT:
  1718.     st[sp] = st[sp+3];
  1719.     if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
  1720.         goto nuts;
  1721.     st[sp] = &str_yes;
  1722.     break;
  1723.     }
  1724.     
  1725.     return sp;
  1726.  
  1727. nuts:
  1728.     if (dowarn)
  1729.     warn("[gs]etsockopt() on closed fd");
  1730.     st[sp] = &str_undef;
  1731.     errno = EBADF;
  1732.     return sp;
  1733.  
  1734. }
  1735.  
  1736. int
  1737. do_getsockname(optype, stab, arglast)
  1738. int optype;
  1739. STAB *stab;
  1740. int *arglast;
  1741. {
  1742.     register STR **st = stack->ary_array;
  1743.     register int sp = arglast[1];
  1744.     register STIO *stio;
  1745.     int fd;
  1746.  
  1747.     if (!stab)
  1748.     goto nuts;
  1749.  
  1750.     stio = stab_io(stab);
  1751.     if (!stio || !stio->ifp)
  1752.     goto nuts;
  1753.  
  1754.     st[sp] = str_2mortal(Str_new(22,257));
  1755.     st[sp]->str_cur = 256;
  1756.     st[sp]->str_pok = 1;
  1757.     fd = fileno(stio->ifp);
  1758.     switch (optype) {
  1759.     case O_GETSOCKNAME:
  1760. #ifdef macintosh
  1761.     if (getsockname(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1762. #else
  1763.     if (getsockname(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1764. #endif
  1765.         goto nuts2;
  1766.     break;
  1767.     case O_GETPEERNAME:
  1768. #ifdef macintosh
  1769.     if (getpeername(fd, (struct sockaddr *) st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1770. #else
  1771.     if (getpeername(fd, st[sp]->str_ptr, (int*)&st[sp]->str_cur) < 0)
  1772. #endif
  1773.         goto nuts2;
  1774.     break;
  1775.     }
  1776.     
  1777.     return sp;
  1778.  
  1779. nuts:
  1780.     if (dowarn)
  1781.     warn("get{sock,peer}name() on closed fd");
  1782.     errno = EBADF;
  1783. nuts2:
  1784.     st[sp] = &str_undef;
  1785.     return sp;
  1786.  
  1787. }
  1788.  
  1789. #ifdef macintosh
  1790. STR *
  1791. do_choose(arglast, maxarg)
  1792.     int *arglast;
  1793.     int maxarg;
  1794. {
  1795.     register STR **st = stack->ary_array;
  1796.     register int sp = arglast[0];
  1797.     int domain, type, flags;
  1798.     char * prompt;
  1799.     char * constraint;
  1800.     char * def_addr;
  1801.     STR * str;
  1802.     
  1803.     domain = (int)str_gnum(st[++sp]);
  1804.     type = (int)str_gnum(st[++sp]);
  1805.     prompt = (char*)str_get(st[++sp]);
  1806.     constraint = (maxarg>=4) ? (char*)str_get(st[++sp]) : nil;
  1807.     constraint = constraint && st[sp]->str_cur ? constraint : nil;
  1808.     flags = (maxarg>=5) ? (int)str_gnum(st[++sp]) : 0;
  1809.     def_addr = (maxarg>=6) ? (char*)str_get(st[++sp]) : nil;
  1810.     def_addr = def_addr && st[sp]->str_cur ? def_addr : nil;
  1811.     
  1812.     str = str_2mortal(Str_new(22,257));
  1813.     str->str_cur = 256;
  1814.     str->str_pok = 1;
  1815.  
  1816.     if (def_addr) {
  1817.         memcpy(str->str_ptr, def_addr, st[sp]->str_cur);
  1818.     str->str_ptr[st[sp]->str_cur] = 0;    /* Some types require this */
  1819.     }
  1820.     
  1821.     if (choose(domain, type, prompt, constraint, flags, str->str_ptr, (int*)&str->str_cur) < 0)
  1822.     goto nuts;
  1823.     
  1824.     return str;
  1825.  
  1826. nuts:
  1827.     return &str_undef;
  1828. }
  1829. #endif
  1830.  
  1831. int
  1832. do_ghent(which,gimme,arglast)
  1833. int which;
  1834. int gimme;
  1835. int *arglast;
  1836. {
  1837.     register ARRAY *ary = stack;
  1838.     register int sp = arglast[0];
  1839.     register char **elem;
  1840.     register STR *str;
  1841.     struct hostent *gethostbyname();
  1842.     struct hostent *gethostbyaddr();
  1843. #ifdef HAS_GETHOSTENT
  1844.     struct hostent *gethostent();
  1845. #endif
  1846.     struct hostent *hent;
  1847.     unsigned long len;
  1848.  
  1849.     if (which == O_GHBYNAME) {
  1850.     char *name = str_get(ary->ary_array[sp+1]);
  1851.  
  1852.     hent = gethostbyname(name);
  1853.     }
  1854.     else if (which == O_GHBYADDR) {
  1855.     STR *addrstr = ary->ary_array[sp+1];
  1856.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1857.     char *addr = str_get(addrstr);
  1858.  
  1859.     hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
  1860.     }
  1861.     else
  1862. #ifdef HAS_GETHOSTENT
  1863.     hent = gethostent();
  1864. #else
  1865.     fatal("gethostent not implemented");
  1866. #endif
  1867.  
  1868. #ifdef HOST_NOT_FOUND
  1869.     if (!hent)
  1870.     statusvalue = (unsigned short)h_errno & 0xffff;
  1871. #endif
  1872.  
  1873.     if (gimme != G_ARRAY) {
  1874.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1875.     if (hent) {
  1876.         if (which == O_GHBYNAME) {
  1877. #ifdef h_addr
  1878.         str_nset(str, *hent->h_addr, hent->h_length);
  1879. #else
  1880.         str_nset(str, hent->h_addr, hent->h_length);
  1881. #endif
  1882.         }
  1883.         else
  1884.         str_set(str, hent->h_name);
  1885.     }
  1886.     return sp;
  1887.     }
  1888.  
  1889.     if (hent) {
  1890. #ifndef lint
  1891.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1892.     str_set(str, hent->h_name);
  1893.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1894.     for (elem = hent->h_aliases; *elem; elem++) {
  1895.         str_cat(str, *elem);
  1896.         if (elem[1])
  1897.         str_ncat(str," ",1);
  1898.     }
  1899.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1900.     str_numset(str, (double)hent->h_addrtype);
  1901.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1902.     len = hent->h_length;
  1903.     str_numset(str, (double)len);
  1904. #ifdef h_addr
  1905.     for (elem = hent->h_addr_list; *elem; elem++) {
  1906.         (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1907.         str_nset(str, *elem, len);
  1908.     }
  1909. #else
  1910.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1911.     str_nset(str, hent->h_addr, len);
  1912. #endif /* h_addr */
  1913. #else /* lint */
  1914.     elem = Nullch;
  1915.     elem = elem;
  1916.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1917. #endif /* lint */
  1918.     }
  1919.  
  1920.     return sp;
  1921. }
  1922.  
  1923. #ifndef macintosh
  1924. int
  1925. do_gnent(which,gimme,arglast)
  1926. int which;
  1927. int gimme;
  1928. int *arglast;
  1929. {
  1930.     register ARRAY *ary = stack;
  1931.     register int sp = arglast[0];
  1932.     register char **elem;
  1933.     register STR *str;
  1934.     struct netent *getnetbyname();
  1935.     struct netent *getnetbyaddr();
  1936.     struct netent *getnetent();
  1937.     struct netent *nent;
  1938.  
  1939.     if (which == O_GNBYNAME) {
  1940.     char *name = str_get(ary->ary_array[sp+1]);
  1941.  
  1942.     nent = getnetbyname(name);
  1943.     }
  1944.     else if (which == O_GNBYADDR) {
  1945.     unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
  1946.     int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
  1947.  
  1948.     nent = getnetbyaddr((long)addr,addrtype);
  1949.     }
  1950.     else
  1951.     nent = getnetent();
  1952.  
  1953.     if (gimme != G_ARRAY) {
  1954.     astore(ary, ++sp, str = str_mortal(&str_undef));
  1955.     if (nent) {
  1956.         if (which == O_GNBYNAME)
  1957.         str_numset(str, (double)nent->n_net);
  1958.         else
  1959.         str_set(str, nent->n_name);
  1960.     }
  1961.     return sp;
  1962.     }
  1963.  
  1964.     if (nent) {
  1965. #ifndef lint
  1966.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1967.     str_set(str, nent->n_name);
  1968.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1969.     for (elem = nent->n_aliases; *elem; elem++) {
  1970.         str_cat(str, *elem);
  1971.         if (elem[1])
  1972.         str_ncat(str," ",1);
  1973.     }
  1974.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1975.     str_numset(str, (double)nent->n_addrtype);
  1976.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  1977.     str_numset(str, (double)nent->n_net);
  1978. #else /* lint */
  1979.     elem = Nullch;
  1980.     elem = elem;
  1981.     (void)astore(ary, ++sp, str_mortal(&str_no));
  1982. #endif /* lint */
  1983.     }
  1984.  
  1985.     return sp;
  1986. }
  1987. #endif
  1988.  
  1989. int
  1990. do_gpent(which,gimme,arglast)
  1991. int which;
  1992. int gimme;
  1993. int *arglast;
  1994. {
  1995.     register ARRAY *ary = stack;
  1996.     register int sp = arglast[0];
  1997.     register char **elem;
  1998.     register STR *str;
  1999.     struct protoent *getprotobyname();
  2000.     struct protoent *getprotobynumber();
  2001.     struct protoent *getprotoent();
  2002.     struct protoent *pent;
  2003.  
  2004.     if (which == O_GPBYNAME) {
  2005.     char *name = str_get(ary->ary_array[sp+1]);
  2006.  
  2007.     pent = getprotobyname(name);
  2008.     }
  2009.     else if (which == O_GPBYNUMBER) {
  2010. #ifndef macintosh
  2011.     int proto = (int)str_gnum(ary->ary_array[sp+1]);
  2012.  
  2013.     pent = getprotobynumber(proto);
  2014. #else
  2015.     fatal("getprotobynumber() not implemented");
  2016. #endif
  2017.     }
  2018.     else
  2019. #ifndef macintosh
  2020.     pent = getprotoent();
  2021. #else
  2022.     fatal("getprotoent() not implemented");
  2023. #endif
  2024.  
  2025.     if (gimme != G_ARRAY) {
  2026.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2027.     if (pent) {
  2028.         if (which == O_GPBYNAME)
  2029.         str_numset(str, (double)pent->p_proto);
  2030.         else
  2031.         str_set(str, pent->p_name);
  2032.     }
  2033.     return sp;
  2034.     }
  2035.  
  2036.     if (pent) {
  2037. #ifndef lint
  2038.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2039.     str_set(str, pent->p_name);
  2040.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2041.     for (elem = pent->p_aliases; *elem; elem++) {
  2042.         str_cat(str, *elem);
  2043.         if (elem[1])
  2044.         str_ncat(str," ",1);
  2045.     }
  2046.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2047.     str_numset(str, (double)pent->p_proto);
  2048. #else /* lint */
  2049.     elem = Nullch;
  2050.     elem = elem;
  2051.     (void)astore(ary, ++sp, str_mortal(&str_no));
  2052. #endif /* lint */
  2053.     }
  2054.  
  2055.     return sp;
  2056. }
  2057.  
  2058. int
  2059. do_gsent(which,gimme,arglast)
  2060. int which;
  2061. int gimme;
  2062. int *arglast;
  2063. {
  2064.     register ARRAY *ary = stack;
  2065.     register int sp = arglast[0];
  2066.     register char **elem;
  2067.     register STR *str;
  2068.     struct servent *getservbyname();
  2069.     struct servent *getservbynumber();
  2070.     struct servent *getservent();
  2071.     struct servent *sent;
  2072.  
  2073.     if (which == O_GSBYNAME) {
  2074.     char *name = str_get(ary->ary_array[sp+1]);
  2075.     char *proto = str_get(ary->ary_array[sp+2]);
  2076.  
  2077.     if (proto && !*proto)
  2078.         proto = Nullch;
  2079.  
  2080.     sent = getservbyname(name,proto);
  2081.     }
  2082.     else if (which == O_GSBYPORT) {
  2083. #ifndef macintosh
  2084.     int port = (int)str_gnum(ary->ary_array[sp+1]);
  2085.     char *proto = str_get(ary->ary_array[sp+2]);
  2086.  
  2087.     sent = getservbyport(port,proto);
  2088. #else
  2089.     fatal("getservbyport() not implemented");
  2090. #endif
  2091.     }
  2092.     else
  2093. #ifndef macintosh
  2094.     sent = getservent();
  2095. #else
  2096.     fatal("getservent() not implemented");
  2097. #endif
  2098.  
  2099.     if (gimme != G_ARRAY) {
  2100.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2101.     if (sent) {
  2102.         if (which == O_GSBYNAME) {
  2103. #ifdef HAS_NTOHS
  2104.         str_numset(str, (double)ntohs(sent->s_port));
  2105. #else
  2106.         str_numset(str, (double)(sent->s_port));
  2107. #endif
  2108.         }
  2109.         else
  2110.         str_set(str, sent->s_name);
  2111.     }
  2112.     return sp;
  2113.     }
  2114.  
  2115.     if (sent) {
  2116. #ifndef lint
  2117.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2118.     str_set(str, sent->s_name);
  2119.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2120.     for (elem = sent->s_aliases; *elem; elem++) {
  2121.         str_cat(str, *elem);
  2122.         if (elem[1])
  2123.         str_ncat(str," ",1);
  2124.     }
  2125.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2126. #ifdef HAS_NTOHS
  2127.     str_numset(str, (double)ntohs(sent->s_port));
  2128. #else
  2129.     str_numset(str, (double)(sent->s_port));
  2130. #endif
  2131.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2132.     str_set(str, sent->s_proto);
  2133. #else /* lint */
  2134.     elem = Nullch;
  2135.     elem = elem;
  2136.     (void)astore(ary, ++sp, str_mortal(&str_no));
  2137. #endif /* lint */
  2138.     }
  2139.  
  2140.     return sp;
  2141. }
  2142.  
  2143. #endif /* HAS_SOCKET */
  2144.  
  2145. #ifdef HAS_SELECT
  2146. int
  2147. do_select(gimme,arglast)
  2148. int gimme;
  2149. int *arglast;
  2150. {
  2151.     register STR **st = stack->ary_array;
  2152.     register int sp = arglast[0];
  2153.     register int i;
  2154.     register int j;
  2155.     register char *s;
  2156.     register STR *str;
  2157.     double value;
  2158.     int maxlen = 0;
  2159.     int nfound;
  2160.     struct timeval timebuf;
  2161.     struct timeval *tbuf = &timebuf;
  2162.     int growsize;
  2163. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2164.     int masksize;
  2165.     int offset;
  2166.     char *fd_sets[4];
  2167.     int k;
  2168.  
  2169. #if BYTEORDER & 0xf0000
  2170. #define ORDERBYTE (0x88888888 - BYTEORDER)
  2171. #else
  2172. #define ORDERBYTE (0x4444 - BYTEORDER)
  2173. #endif
  2174.  
  2175. #endif
  2176.  
  2177.     for (i = 1; i <= 3; i++) {
  2178.     j = st[sp+i]->str_cur;
  2179.     if (maxlen < j)
  2180.         maxlen = j;
  2181.     }
  2182.  
  2183. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2184.     growsize = maxlen;        /* little endians can use vecs directly */
  2185. #else
  2186. #ifdef NFDBITS
  2187.  
  2188. #ifndef NBBY
  2189. #define NBBY 8
  2190. #endif
  2191.  
  2192.     masksize = NFDBITS / NBBY;
  2193. #else
  2194.     masksize = sizeof(long);    /* documented int, everyone seems to use long */
  2195. #endif
  2196.     growsize = maxlen + (masksize - (maxlen % masksize));
  2197.     Zero(&fd_sets[0], 4, char*);
  2198. #endif
  2199.  
  2200.     for (i = 1; i <= 3; i++) {
  2201.     str = st[sp+i];
  2202.     j = str->str_len;
  2203.     if (j < growsize) {
  2204.         if (str->str_pok) {
  2205.         Str_Grow(str,growsize);
  2206.         s = str_get(str) + j;
  2207.         while (++j <= growsize) {
  2208.             *s++ = '\0';
  2209.         }
  2210.         }
  2211.         else if (str->str_ptr) {
  2212.         Safefree(str->str_ptr);
  2213.         str->str_ptr = Nullch;
  2214.         }
  2215.     }
  2216. #if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
  2217.     s = str->str_ptr;
  2218.     if (s) {
  2219.         New(403, fd_sets[i], growsize, char);
  2220.         for (offset = 0; offset < growsize; offset += masksize) {
  2221.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2222.             fd_sets[i][j+offset] = s[(k % masksize) + offset];
  2223.         }
  2224.     }
  2225. #endif
  2226.     }
  2227.     str = st[sp+4];
  2228.     if (str->str_nok || str->str_pok) {
  2229.     value = str_gnum(str);
  2230.     if (value < 0.0)
  2231.         value = 0.0;
  2232.     timebuf.tv_sec = (long)value;
  2233.     value -= (double)timebuf.tv_sec;
  2234.     timebuf.tv_usec = (long)(value * 1000000.0);
  2235.     }
  2236.     else
  2237.     tbuf = Null(struct timeval*);
  2238.  
  2239. #if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
  2240.     nfound = select(
  2241.     maxlen * 8,
  2242.     st[sp+1]->str_ptr,
  2243.     st[sp+2]->str_ptr,
  2244.     st[sp+3]->str_ptr,
  2245.     tbuf);
  2246. #else
  2247.     nfound = select(
  2248.     maxlen * 8,
  2249.     fd_sets[1],
  2250.     fd_sets[2],
  2251.     fd_sets[3],
  2252.     tbuf);
  2253.     for (i = 1; i <= 3; i++) {
  2254.     if (fd_sets[i]) {
  2255.         str = st[sp+i];
  2256.         s = str->str_ptr;
  2257.         for (offset = 0; offset < growsize; offset += masksize) {
  2258.         for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
  2259.             s[(k % masksize) + offset] = fd_sets[i][j+offset];
  2260.         }
  2261.         Safefree(fd_sets[i]);
  2262.     }
  2263.     }
  2264. #endif
  2265.  
  2266.     st[++sp] = str_mortal(&str_no);
  2267.     str_numset(st[sp], (double)nfound);
  2268.     if (gimme == G_ARRAY && tbuf) {
  2269.     value = (double)(timebuf.tv_sec) +
  2270.         (double)(timebuf.tv_usec) / 1000000.0;
  2271.     st[++sp] = str_mortal(&str_no);
  2272.     str_numset(st[sp], value);
  2273.     }
  2274.     return sp;
  2275. }
  2276. #endif /* SELECT */
  2277.  
  2278. #ifdef HAS_SOCKET
  2279. int
  2280. do_spair(stab1, stab2, arglast)
  2281. STAB *stab1;
  2282. STAB *stab2;
  2283. int *arglast;
  2284. {
  2285.     register STR **st = stack->ary_array;
  2286.     register int sp = arglast[2];
  2287.     register STIO *stio1;
  2288.     register STIO *stio2;
  2289.     int domain, type, protocol, fd[2];
  2290.  
  2291.     if (!stab1 || !stab2)
  2292.     return FALSE;
  2293.  
  2294.     stio1 = stab_io(stab1);
  2295.     stio2 = stab_io(stab2);
  2296.     if (!stio1)
  2297.     stio1 = stab_io(stab1) = stio_new();
  2298.     else if (stio1->ifp)
  2299.     do_close(stab1,FALSE);
  2300.     if (!stio2)
  2301.     stio2 = stab_io(stab2) = stio_new();
  2302.     else if (stio2->ifp)
  2303.     do_close(stab2,FALSE);
  2304.  
  2305.     domain = (int)str_gnum(st[++sp]);
  2306.     type = (int)str_gnum(st[++sp]);
  2307.     protocol = (int)str_gnum(st[++sp]);
  2308. #ifdef TAINT
  2309.     taintproper("Insecure dependency in socketpair");
  2310. #endif
  2311. #ifdef HAS_SOCKETPAIR
  2312.     if (socketpair(domain,type,protocol,fd) < 0)
  2313.     return FALSE;
  2314. #else
  2315.     fatal("Socketpair unimplemented");
  2316. #endif
  2317.     stio1->ifp = fdopen(fd[0], "r");
  2318.     stio1->ofp = fdopen(fd[0], "w");
  2319.     stio1->type = 's';
  2320.     stio2->ifp = fdopen(fd[1], "r");
  2321.     stio2->ofp = fdopen(fd[1], "w");
  2322.     stio2->type = 's';
  2323.     if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
  2324.     if (stio1->ifp) fclose(stio1->ifp);
  2325.     if (stio1->ofp) fclose(stio1->ofp);
  2326.     if (!stio1->ifp && !stio1->ofp) close(fd[0]);
  2327.     if (stio2->ifp) fclose(stio2->ifp);
  2328.     if (stio2->ofp) fclose(stio2->ofp);
  2329.     if (!stio2->ifp && !stio2->ofp) close(fd[1]);
  2330.     return FALSE;
  2331.     }
  2332.  
  2333.     return TRUE;
  2334. }
  2335.  
  2336. #endif /* HAS_SOCKET */
  2337.  
  2338. int
  2339. do_gpwent(which,gimme,arglast)
  2340. int which;
  2341. int gimme;
  2342. int *arglast;
  2343. {
  2344. #ifdef I_PWD
  2345.     register ARRAY *ary = stack;
  2346.     register int sp = arglast[0];
  2347.     register STR *str;
  2348.     struct passwd *getpwnam();
  2349.     struct passwd *getpwuid();
  2350.     struct passwd *getpwent();
  2351.     struct passwd *pwent;
  2352.  
  2353.     if (which == O_GPWNAM) {
  2354.     char *name = str_get(ary->ary_array[sp+1]);
  2355.  
  2356.     pwent = getpwnam(name);
  2357.     }
  2358.     else if (which == O_GPWUID) {
  2359.     int uid = (int)str_gnum(ary->ary_array[sp+1]);
  2360.  
  2361.     pwent = getpwuid(uid);
  2362.     }
  2363.     else
  2364.     pwent = getpwent();
  2365.  
  2366.     if (gimme != G_ARRAY) {
  2367.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2368.     if (pwent) {
  2369.         if (which == O_GPWNAM)
  2370.         str_numset(str, (double)pwent->pw_uid);
  2371.         else
  2372.         str_set(str, pwent->pw_name);
  2373.     }
  2374.     return sp;
  2375.     }
  2376.  
  2377.     if (pwent) {
  2378.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2379.     str_set(str, pwent->pw_name);
  2380.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2381.     str_set(str, pwent->pw_passwd);
  2382.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2383.     str_numset(str, (double)pwent->pw_uid);
  2384.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2385.     str_numset(str, (double)pwent->pw_gid);
  2386.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2387. #ifdef PWCHANGE
  2388.     str_numset(str, (double)pwent->pw_change);
  2389. #else
  2390. #ifdef PWQUOTA
  2391.     str_numset(str, (double)pwent->pw_quota);
  2392. #else
  2393. #ifdef PWAGE
  2394.     str_set(str, pwent->pw_age);
  2395. #endif
  2396. #endif
  2397. #endif
  2398.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2399. #ifdef PWCLASS
  2400.     str_set(str,pwent->pw_class);
  2401. #else
  2402. #ifdef PWCOMMENT
  2403.     str_set(str, pwent->pw_comment);
  2404. #endif
  2405. #endif
  2406.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2407.     str_set(str, pwent->pw_gecos);
  2408.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2409.     str_set(str, pwent->pw_dir);
  2410.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2411.     str_set(str, pwent->pw_shell);
  2412. #ifdef PWEXPIRE
  2413.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2414.     str_numset(str, (double)pwent->pw_expire);
  2415. #endif
  2416.     }
  2417.  
  2418.     return sp;
  2419. #else
  2420.     fatal("password routines not implemented");
  2421. #endif
  2422. }
  2423.  
  2424. int
  2425. do_ggrent(which,gimme,arglast)
  2426. int which;
  2427. int gimme;
  2428. int *arglast;
  2429. {
  2430. #ifdef I_GRP
  2431.     register ARRAY *ary = stack;
  2432.     register int sp = arglast[0];
  2433.     register char **elem;
  2434.     register STR *str;
  2435.     struct group *getgrnam();
  2436.     struct group *getgrgid();
  2437.     struct group *getgrent();
  2438.     struct group *grent;
  2439.  
  2440.     if (which == O_GGRNAM) {
  2441.     char *name = str_get(ary->ary_array[sp+1]);
  2442.  
  2443.     grent = getgrnam(name);
  2444.     }
  2445.     else if (which == O_GGRGID) {
  2446.     int gid = (int)str_gnum(ary->ary_array[sp+1]);
  2447.  
  2448.     grent = getgrgid(gid);
  2449.     }
  2450.     else
  2451.     grent = getgrent();
  2452.  
  2453.     if (gimme != G_ARRAY) {
  2454.     astore(ary, ++sp, str = str_mortal(&str_undef));
  2455.     if (grent) {
  2456.         if (which == O_GGRNAM)
  2457.         str_numset(str, (double)grent->gr_gid);
  2458.         else
  2459.         str_set(str, grent->gr_name);
  2460.     }
  2461.     return sp;
  2462.     }
  2463.  
  2464.     if (grent) {
  2465.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2466.     str_set(str, grent->gr_name);
  2467.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2468.     str_set(str, grent->gr_passwd);
  2469.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2470.     str_numset(str, (double)grent->gr_gid);
  2471.     (void)astore(ary, ++sp, str = str_mortal(&str_no));
  2472.     for (elem = grent->gr_mem; *elem; elem++) {
  2473.         str_cat(str, *elem);
  2474.         if (elem[1])
  2475.         str_ncat(str," ",1);
  2476.     }
  2477.     }
  2478.  
  2479.     return sp;
  2480. #else
  2481.     fatal("group routines not implemented");
  2482. #endif
  2483. }
  2484.  
  2485. int
  2486. do_dirop(optype,stab,gimme,arglast)
  2487. int optype;
  2488. STAB *stab;
  2489. int gimme;
  2490. int *arglast;
  2491. {
  2492. #if defined(DIRENT) && defined(HAS_READDIR)
  2493.     register ARRAY *ary = stack;
  2494.     register STR **st = ary->ary_array;
  2495.     register int sp = arglast[1];
  2496.     register STIO *stio;
  2497.     long along;
  2498. #ifndef apollo
  2499.     struct DIRENT *readdir();
  2500. #endif
  2501.     register struct DIRENT *dp;
  2502.  
  2503.     if (!stab)
  2504.     goto nope;
  2505.     if (!(stio = stab_io(stab)))
  2506.     stio = stab_io(stab) = stio_new();
  2507.     if (!stio->dirp && optype != O_OPEN_DIR)
  2508.     goto nope;
  2509.     st[sp] = &str_yes;
  2510.     switch (optype) {
  2511.     case O_OPEN_DIR:
  2512.     if (stio->dirp)
  2513.         closedir(stio->dirp);
  2514.     if (!(stio->dirp = opendir(str_get(st[sp+1]))))
  2515.         goto nope;
  2516.     break;
  2517.     case O_READDIR:
  2518.     if (gimme == G_ARRAY) {
  2519.         --sp;
  2520.         /*SUPPRESS 560*/
  2521.         while (dp = readdir(stio->dirp)) {
  2522. #ifdef DIRNAMLEN
  2523.         (void)astore(ary,++sp,
  2524.           str_2mortal(str_make(dp->d_name,dp->d_namlen)));
  2525. #else
  2526.         (void)astore(ary,++sp,
  2527.           str_2mortal(str_make(dp->d_name,0)));
  2528. #endif
  2529.         }
  2530.     }
  2531.     else {
  2532.         if (!(dp = readdir(stio->dirp)))
  2533.         goto nope;
  2534.         st[sp] = str_mortal(&str_undef);
  2535. #ifdef DIRNAMLEN
  2536.         str_nset(st[sp], dp->d_name, dp->d_namlen);
  2537. #else
  2538.         str_set(st[sp], dp->d_name);
  2539. #endif
  2540.     }
  2541.     break;
  2542. #if MACH
  2543.     case O_TELLDIR:
  2544.     case O_SEEKDIR:
  2545.         goto nope;
  2546. #else
  2547.     case O_TELLDIR:
  2548.     st[sp] = str_mortal(&str_undef);
  2549.     str_numset(st[sp], (double)telldir(stio->dirp));
  2550.     break;
  2551.     case O_SEEKDIR:
  2552.     st[sp] = str_mortal(&str_undef);
  2553.     along = (long)str_gnum(st[sp+1]);
  2554. #ifndef macintosh
  2555.     (void)seekdir(stio->dirp,along);
  2556. #else
  2557.     seekdir(stio->dirp,along);
  2558. #endif
  2559.     break;
  2560. #endif
  2561.     case O_REWINDDIR:
  2562.     st[sp] = str_mortal(&str_undef);
  2563. #ifndef macintosh
  2564.     (void)rewinddir(stio->dirp);
  2565. #else
  2566.     rewinddir(stio->dirp);
  2567. #endif
  2568.     break;
  2569.     case O_CLOSEDIR:
  2570.     st[sp] = str_mortal(&str_undef);
  2571. #ifndef macintosh
  2572.     (void)closedir(stio->dirp);
  2573. #else
  2574.     closedir(stio->dirp);
  2575. #endif
  2576.     stio->dirp = 0;
  2577.     break;
  2578.     }
  2579.     return sp;
  2580.  
  2581. nope:
  2582.     st[sp] = &str_undef;
  2583.     if (!errno)
  2584.     errno = EBADF;
  2585.     return sp;
  2586.  
  2587. #endif
  2588. phooey:
  2589.     fatal("Unimplemented directory operation");
  2590. }
  2591.  
  2592. int
  2593. apply(type,arglast)
  2594. int type;
  2595. int *arglast;
  2596. {
  2597.     register STR **st = stack->ary_array;
  2598.     register int sp = arglast[1];
  2599.     register int items = arglast[2] - sp;
  2600.     register int val;
  2601.     register int val2;
  2602.     register int tot = 0;
  2603.     char *s;
  2604.  
  2605. #ifdef TAINT
  2606.     for (st += ++sp; items--; st++)
  2607.     tainted |= (*st)->str_tainted;
  2608.     st = stack->ary_array;
  2609.     sp = arglast[1];
  2610.     items = arglast[2] - sp;
  2611. #endif
  2612.     switch (type) {
  2613.     case O_CHMOD:
  2614. #ifdef TAINT
  2615.     taintproper("Insecure dependency in chmod");
  2616. #endif
  2617.     if (--items > 0) {
  2618.         tot = items;
  2619.         val = (int)str_gnum(st[++sp]);
  2620.         while (items--) {
  2621.         if (chmod(str_get(st[++sp]),val))
  2622.             tot--;
  2623.         }
  2624.     }
  2625.     break;
  2626. #ifdef HAS_CHOWN
  2627.     case O_CHOWN:
  2628. #ifdef TAINT
  2629.     taintproper("Insecure dependency in chown");
  2630. #endif
  2631.     if (items > 2) {
  2632.         items -= 2;
  2633.         tot = items;
  2634.         val = (int)str_gnum(st[++sp]);
  2635.         val2 = (int)str_gnum(st[++sp]);
  2636.         while (items--) {
  2637.         if (chown(str_get(st[++sp]),val,val2))
  2638.             tot--;
  2639.         }
  2640.     }
  2641.     break;
  2642. #endif
  2643. #ifdef HAS_KILL
  2644.     case O_KILL:
  2645. #ifdef TAINT
  2646.     taintproper("Insecure dependency in kill");
  2647. #endif
  2648.     if (--items > 0) {
  2649.         tot = items;
  2650.         s = str_get(st[++sp]);
  2651.         if (isUPPER(*s)) {
  2652.         if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
  2653.             s += 3;
  2654.         if (!(val = whichsig(s)))
  2655.             fatal("Unrecognized signal name \"%s\"",s);
  2656.         }
  2657.         else
  2658.         val = (int)str_gnum(st[sp]);
  2659.         if (val < 0) {
  2660.         val = -val;
  2661.         while (items--) {
  2662.             int proc = (int)str_gnum(st[++sp]);
  2663. #ifdef HAS_KILLPG
  2664.             if (killpg(proc,val))    /* BSD */
  2665. #else
  2666.             if (kill(-proc,val))    /* SYSV */
  2667. #endif
  2668.             tot--;
  2669.         }
  2670.         }
  2671.         else {
  2672.         while (items--) {
  2673.             if (kill((int)(str_gnum(st[++sp])),val))
  2674.             tot--;
  2675.         }
  2676.         }
  2677.     }
  2678.     break;
  2679. #endif
  2680.     case O_UNLINK:
  2681. #ifdef TAINT
  2682.     taintproper("Insecure dependency in unlink");
  2683. #endif
  2684.     tot = items;
  2685.     while (items--) {
  2686.         s = str_get(st[++sp]);
  2687.         if (euid || unsafe) {
  2688.             if (UNLINK(s))
  2689.                 tot--;
  2690.         }
  2691.         else {    /* don't let root wipe out directories without -U */
  2692. #ifdef HAS_LSTAT
  2693.         if (lstat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2694. #else
  2695.         if (stat(s,&statbuf) < 0 || S_ISDIR(statbuf.st_mode))
  2696. #endif
  2697.             tot--;
  2698.         else {
  2699.             if (UNLINK(s))
  2700.             tot--;
  2701.         }
  2702.         }
  2703.     }
  2704.     break;
  2705.     case O_UTIME:
  2706. #ifdef TAINT
  2707.     taintproper("Insecure dependency in utime");
  2708. #endif
  2709.     if (items > 2) {
  2710. #ifdef I_UTIME
  2711.         struct utimbuf utbuf;
  2712. #else
  2713.         struct {
  2714.         long    actime;
  2715.         long    modtime;
  2716.         } utbuf;
  2717. #endif
  2718.  
  2719.         Zero(&utbuf, sizeof utbuf, char);
  2720.         utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
  2721.         utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
  2722.         items -= 2;
  2723. #ifndef lint
  2724.         tot = items;
  2725.         while (items--) {
  2726.         if (utime(str_get(st[++sp]),&utbuf))
  2727.             tot--;
  2728.         }
  2729. #endif
  2730.     }
  2731.     else
  2732.         items = 0;
  2733.     break;
  2734.     }
  2735.     return tot;
  2736. }
  2737.  
  2738. /* Do the permissions allow some operation?  Assumes statcache already set. */
  2739.  
  2740. int
  2741. cando(bit, effective, statbufp)
  2742. int bit;
  2743. int effective;
  2744. register struct stat *statbufp;
  2745. {
  2746. #ifdef NIXUNIX
  2747.     /* [Comments and code from Len Reed]
  2748.      * MS-DOS "user" is similar to UNIX's "superuser," but can't write
  2749.      * to write-protected files.  The execute permission bit is set
  2750.      * by the Miscrosoft C library stat() function for the following:
  2751.      *        .exe files
  2752.      *        .com files
  2753.      *        .bat files
  2754.      *        directories
  2755.      * All files and directories are readable.
  2756.      * Directories and special files, e.g. "CON", cannot be
  2757.      * write-protected.
  2758.      * [Comment by Tom Dinger -- a directory can have the write-protect
  2759.      *        bit set in the file system, but DOS permits changes to
  2760.      *        the directory anyway.  In addition, all bets are off
  2761.      *        here for networked software, such as Novell and
  2762.      *        Sun's PC-NFS.]
  2763.      */
  2764.  
  2765.      /* Atari stat() does pretty much the same thing. we set x_bit_set_in_stat
  2766.       * too so it will actually look into the files for magic numbers
  2767.       */
  2768.      return (bit & statbufp->st_mode) ? TRUE : FALSE;
  2769.  
  2770. #else /* ! NIXUNIX */
  2771.     if ((effective ? euid : uid) == 0) {    /* root is special */
  2772.     if (bit == S_IXUSR) {
  2773.         if (statbufp->st_mode & 0111 || S_ISDIR(statbufp->st_mode))
  2774.         return TRUE;
  2775.     }
  2776.     else
  2777.         return TRUE;        /* root reads and writes anything */
  2778.     return FALSE;
  2779.     }
  2780.     if (statbufp->st_uid == (effective ? euid : uid) ) {
  2781.     if (statbufp->st_mode & bit)
  2782.         return TRUE;    /* ok as "user" */
  2783.     }
  2784.     else if (ingroup((int)statbufp->st_gid,effective)) {
  2785.     if (statbufp->st_mode & bit >> 3)
  2786.         return TRUE;    /* ok as "group" */
  2787.     }
  2788.     else if (statbufp->st_mode & bit >> 6)
  2789.     return TRUE;    /* ok as "other" */
  2790.     return FALSE;
  2791. #endif /* ! MSDOS */
  2792. }
  2793.  
  2794. int
  2795. ingroup(testgid,effective)
  2796. int testgid;
  2797. int effective;
  2798. {
  2799. #ifdef macintosh
  2800.     /* This is simply not correct for AppleShare, but fix it yerself. */
  2801.     return TRUE;
  2802. #else
  2803.     if (testgid == (effective ? egid : gid))
  2804.     return TRUE;
  2805. #ifdef HAS_GETGROUPS
  2806. #ifndef NGROUPS
  2807. #define NGROUPS 32
  2808. #endif
  2809.     {
  2810.     GROUPSTYPE gary[NGROUPS];
  2811.     int anum;
  2812.  
  2813.     anum = getgroups(NGROUPS,gary);
  2814.     while (--anum >= 0)
  2815.         if (gary[anum] == testgid)
  2816.         return TRUE;
  2817.     }
  2818. #endif
  2819.     return FALSE;
  2820. #endif
  2821. }
  2822.  
  2823. #if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
  2824.  
  2825. int
  2826. do_ipcget(optype, arglast)
  2827. int optype;
  2828. int *arglast;
  2829. {
  2830.     register STR **st = stack->ary_array;
  2831.     register int sp = arglast[0];
  2832.     key_t key;
  2833.     int n, flags;
  2834.  
  2835.     key = (key_t)str_gnum(st[++sp]);
  2836.     n = (optype == O_MSGGET) ? 0 : (int)str_gnum(st[++sp]);
  2837.     flags = (int)str_gnum(st[++sp]);
  2838.     errno = 0;
  2839.     switch (optype)
  2840.     {
  2841. #ifdef HAS_MSG
  2842.     case O_MSGGET:
  2843.     return msgget(key, flags);
  2844. #endif
  2845. #ifdef HAS_SEM
  2846.     case O_SEMGET:
  2847.     return semget(key, n, flags);
  2848. #endif
  2849. #ifdef HAS_SHM
  2850.     case O_SHMGET:
  2851.     return shmget(key, n, flags);
  2852. #endif
  2853. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2854.     default:
  2855.     fatal("%s not implemented", opname[optype]);
  2856. #endif
  2857.     }
  2858.     return -1;            /* should never happen */
  2859. }
  2860.  
  2861. int
  2862. do_ipcctl(optype, arglast)
  2863. int optype;
  2864. int *arglast;
  2865. {
  2866.     register STR **st = stack->ary_array;
  2867.     register int sp = arglast[0];
  2868.     STR *astr;
  2869.     char *a;
  2870.     int id, n, cmd, infosize, getinfo, ret;
  2871.  
  2872.     id = (int)str_gnum(st[++sp]);
  2873.     n = (optype == O_SEMCTL) ? (int)str_gnum(st[++sp]) : 0;
  2874.     cmd = (int)str_gnum(st[++sp]);
  2875.     astr = st[++sp];
  2876.  
  2877.     infosize = 0;
  2878.     getinfo = (cmd == IPC_STAT);
  2879.  
  2880.     switch (optype)
  2881.     {
  2882. #ifdef HAS_MSG
  2883.     case O_MSGCTL:
  2884.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2885.         infosize = sizeof(struct msqid_ds);
  2886.     break;
  2887. #endif
  2888. #ifdef HAS_SHM
  2889.     case O_SHMCTL:
  2890.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2891.         infosize = sizeof(struct shmid_ds);
  2892.     break;
  2893. #endif
  2894. #ifdef HAS_SEM
  2895.     case O_SEMCTL:
  2896.     if (cmd == IPC_STAT || cmd == IPC_SET)
  2897.         infosize = sizeof(struct semid_ds);
  2898.     else if (cmd == GETALL || cmd == SETALL)
  2899.     {
  2900.         struct semid_ds semds;
  2901.         if (semctl(id, 0, IPC_STAT, &semds) == -1)
  2902.         return -1;
  2903.         getinfo = (cmd == GETALL);
  2904.         infosize = semds.sem_nsems * sizeof(short);
  2905.         /* "short" is technically wrong but much more portable
  2906.            than guessing about u_?short(_t)? */
  2907.     }
  2908.     break;
  2909. #endif
  2910. #if !defined(HAS_MSG) || !defined(HAS_SEM) || !defined(HAS_SHM)
  2911.     default:
  2912.     fatal("%s not implemented", opname[optype]);
  2913. #endif
  2914.     }
  2915.  
  2916.     if (infosize)
  2917.     {
  2918.     if (getinfo)
  2919.     {
  2920.         STR_GROW(astr, infosize+1);
  2921.         a = str_get(astr);
  2922.     }
  2923.     else
  2924.     {
  2925.         a = str_get(astr);
  2926.         if (astr->str_cur != infosize)
  2927.         {
  2928.         errno = EINVAL;
  2929.         return -1;
  2930.         }
  2931.     }
  2932.     }
  2933.     else
  2934.     {
  2935.     int i = (int)str_gnum(astr);
  2936.     a = (char *)i;        /* ouch */
  2937.     }
  2938.     errno = 0;
  2939.     switch (optype)
  2940.     {
  2941. #ifdef HAS_MSG
  2942.     case O_MSGCTL:
  2943.     ret = msgctl(id, cmd, (struct msqid_ds *)a);
  2944.     break;
  2945. #endif
  2946. #ifdef HAS_SEM
  2947.     case O_SEMCTL:
  2948.     ret = semctl(id, n, cmd, a);
  2949.     break;
  2950. #endif
  2951. #ifdef HAS_SHM
  2952.     case O_SHMCTL:
  2953.     ret = shmctl(id, cmd, (struct shmid_ds *)a);
  2954.     break;
  2955. #endif
  2956.     }
  2957.     if (getinfo && ret >= 0) {
  2958.     astr->str_cur = infosize;
  2959.     astr->str_ptr[infosize] = '\0';
  2960.     }
  2961.     return ret;
  2962. }
  2963.  
  2964. int
  2965. do_msgsnd(arglast)
  2966. int *arglast;
  2967. {
  2968. #ifdef HAS_MSG
  2969.     register STR **st = stack->ary_array;
  2970.     register int sp = arglast[0];
  2971.     STR *mstr;
  2972.     char *mbuf;
  2973.     int id, msize, flags;
  2974.  
  2975.     id = (int)str_gnum(st[++sp]);
  2976.     mstr = st[++sp];
  2977.     flags = (int)str_gnum(st[++sp]);
  2978.     mbuf = str_get(mstr);
  2979.     if ((msize = mstr->str_cur - sizeof(long)) < 0) {
  2980.     errno = EINVAL;
  2981.     return -1;
  2982.     }
  2983.     errno = 0;
  2984.     return msgsnd(id, (struct msgbuf *)mbuf, msize, flags);
  2985. #else
  2986.     fatal("msgsnd not implemented");
  2987. #endif
  2988. }
  2989.  
  2990. int
  2991. do_msgrcv(arglast)
  2992. int *arglast;
  2993. {
  2994. #ifdef HAS_MSG
  2995.     register STR **st = stack->ary_array;
  2996.     register int sp = arglast[0];
  2997.     STR *mstr;
  2998.     char *mbuf;
  2999.     long mtype;
  3000.     int id, msize, flags, ret;
  3001.  
  3002.     id = (int)str_gnum(st[++sp]);
  3003.     mstr = st[++sp];
  3004.     msize = (int)str_gnum(st[++sp]);
  3005.     mtype = (long)str_gnum(st[++sp]);
  3006.     flags = (int)str_gnum(st[++sp]);
  3007.     mbuf = str_get(mstr);
  3008.     if (mstr->str_cur < sizeof(long)+msize+1) {
  3009.     STR_GROW(mstr, sizeof(long)+msize+1);
  3010.     mbuf = str_get(mstr);
  3011.     }
  3012.     errno = 0;
  3013.     ret = msgrcv(id, (struct msgbuf *)mbuf, msize, mtype, flags);
  3014.     if (ret >= 0) {
  3015.     mstr->str_cur = sizeof(long)+ret;
  3016.     mstr->str_ptr[sizeof(long)+ret] = '\0';
  3017.     }
  3018.     return ret;
  3019. #else
  3020.     fatal("msgrcv not implemented");
  3021. #endif
  3022. }
  3023.  
  3024. int
  3025. do_semop(arglast)
  3026. int *arglast;
  3027. {
  3028. #ifdef HAS_SEM
  3029.     register STR **st = stack->ary_array;
  3030.     register int sp = arglast[0];
  3031.     STR *opstr;
  3032.     char *opbuf;
  3033.     int id, opsize;
  3034.  
  3035.     id = (int)str_gnum(st[++sp]);
  3036.     opstr = st[++sp];
  3037.     opbuf = str_get(opstr);
  3038.     opsize = opstr->str_cur;
  3039.     if (opsize < sizeof(struct sembuf)
  3040.     || (opsize % sizeof(struct sembuf)) != 0) {
  3041.     errno = EINVAL;
  3042.     return -1;
  3043.     }
  3044.     errno = 0;
  3045.     return semop(id, (struct sembuf *)opbuf, opsize/sizeof(struct sembuf));
  3046. #else
  3047.     fatal("semop not implemented");
  3048. #endif
  3049. }
  3050.  
  3051. int
  3052. do_shmio(optype, arglast)
  3053. int optype;
  3054. int *arglast;
  3055. {
  3056. #ifdef HAS_SHM
  3057.     register STR **st = stack->ary_array;
  3058.     register int sp = arglast[0];
  3059.     STR *mstr;
  3060.     char *mbuf, *shm;
  3061.     int id, mpos, msize;
  3062.     struct shmid_ds shmds;
  3063. #ifndef VOIDSHMAT
  3064.     extern char *shmat();
  3065. #endif
  3066.  
  3067.     id = (int)str_gnum(st[++sp]);
  3068.     mstr = st[++sp];
  3069.     mpos = (int)str_gnum(st[++sp]);
  3070.     msize = (int)str_gnum(st[++sp]);
  3071.     errno = 0;
  3072.     if (shmctl(id, IPC_STAT, &shmds) == -1)
  3073.     return -1;
  3074.     if (mpos < 0 || msize < 0 || mpos + msize > shmds.shm_segsz) {
  3075.     errno = EFAULT;        /* can't do as caller requested */
  3076.     return -1;
  3077.     }
  3078.     shm = (char*)shmat(id, (char*)NULL, (optype == O_SHMREAD) ? SHM_RDONLY : 0);
  3079.     if (shm == (char *)-1)    /* I hate System V IPC, I really do */
  3080.     return -1;
  3081.     mbuf = str_get(mstr);
  3082.     if (optype == O_SHMREAD) {
  3083.     if (mstr->str_cur < msize) {
  3084.         STR_GROW(mstr, msize+1);
  3085.         mbuf = str_get(mstr);
  3086.     }
  3087.     Copy(shm + mpos, mbuf, msize, char);
  3088.     mstr->str_cur = msize;
  3089.     mstr->str_ptr[msize] = '\0';
  3090.     }
  3091.     else {
  3092.     int n;
  3093.  
  3094.     if ((n = mstr->str_cur) > msize)
  3095.         n = msize;
  3096.     Copy(mbuf, shm + mpos, n, char);
  3097.     if (n < msize)
  3098.         memzero(shm + mpos + n, msize - n);
  3099.     }
  3100.     return shmdt(shm);
  3101. #else
  3102.     fatal("shm I/O not implemented");
  3103. #endif
  3104. }
  3105.  
  3106. #endif /* SYSV IPC */
  3107.  
  3108. void init_doio()
  3109. {
  3110.     laststatval = -1;
  3111.     laststype   = O_STAT;
  3112.     Argv = Null(char **);
  3113.     Cmd = Nullch;
  3114. }
  3115.